home *** CD-ROM | disk | FTP | other *** search
Text File | 1987-04-22 | 219.5 KB | 5,736 lines |
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Your Second
- GFA-BASIC 3.0
- Manual
-
-
-
- Second Edition
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- (c) Han Kempen
- Coevorden, 1990
-
-
-
-
-
-
-
-
-
-
- Everything you always wanted to know about
- GFA-Basic 3.0, but were afraid to ask
-
- CONTENTS
-
-
- INTRODUCTION .......................... 7
-
- 1. GENERAL
- Start-up .............................. 9
- Application ........................... 9
- Monitor ............................... 10
- Break ................................. 10
- Operating System ...................... 10
-
- 2. THE EDITOR
- Abbreviated Commands .................. 12
- Syntax ................................ 12
- Folded Procedures ..................... 13
- Tab ................................... 13
- Cut and Paste ......................... 13
- Load .................................. 13
- Save .................................. 14
- Llist ................................. 14
- Insert-mode ........................... 15
- Direct mode ........................... 15
- DEFLIST ............................... 15
- Special Characters .................... 16
-
- 3. VARIABLES
- Variable Type ......................... 17
- DEFWRD ................................ 17
- Boolean ............................... 17
- Integer ............................... 18
- Floating Point ........................ 18
- VAR ................................... 18
- FUNCTION .............................. 19
- CLEAR ................................. 19
- ERASE ................................. 19
- DUMP .................................. 19
- TYPE .................................. 20
- READ .................................. 20
- SWAP .................................. 20
- TIME$ ................................. 21
- TIMER ................................. 21
- DATE$ ................................. 22
-
- 4. MEMORY
- RAM ................................... 23
- INT{} ................................. 23
- RESERVE ............................... 23
- INLINE ................................ 24
- MALLOC ................................ 25
-
- 5. SORT
- QSORT v. SSORT ........................ 26
- QSORT of number-arrays ................ 26
- QSORT of string-arrays ................ 26
-
- 6. OPERATORS and NUMERICAL FUNCTIONS
- \ ..................................... 29
- PRED and SUCC ......................... 29
- MOD ................................... 29
- BCLR .................................. 29
- BSET .................................. 30
- BCHG .................................. 30
- LOG ................................... 30
- SINQ and COSQ ......................... 30
- EQV ................................... 31
- CARD and SWAP ......................... 31
- MAX ................................... 31
- Correlation ........................... 31
-
- 7. STRINGS
- INSTR ................................. 32
- LSET and RSET ......................... 32
- Parser ................................ 32
-
- 8. KEYBOARD INPUT
- INKEY$ ................................ 33
- INPUT ................................. 34
- INPUT$ ................................ 35
- LINE INPUT ............................ 35
- KEYTEST ............................... 35
- KEYGET ................................ 35
- KEYLOOK ............................... 36
- KEYPRESS .............................. 37
- KEYDEF ................................ 37
- Keyboard .............................. 37
- Keyclick, Keyrepeat and CapsLock ...... 38
-
- 9. SCREEN OUTPUT
- PRINT ................................. 40
- LOCATE ................................ 41
- PRINT TAB ............................. 42
- Setscreen (XBIOS 5) ................... 42
- Font .................................. 43
-
- 10. PRINTER
- Printer ready ......................... 45
- HARDCOPY .............................. 45
- Printer-commands ...................... 47
-
- 11. FILES
- Floppy Write Test ..................... 50
- Step Rate ............................. 50
- RAM-disk .............................. 50
- DIR$() ................................ 50
- DIR and FILES ......................... 51
- FSFIRST and FSNEXT .................... 52
- EXIST ................................. 54
- LOF ................................... 54
- TOUCH ................................. 54
- NAME .................................. 54
- KILL .................................. 54
- File Copy ............................. 55
- Disk Format ........................... 55
- File Allocation Table (FAT) ........... 58
- Sectors ............................... 59
- Bootsector ............................ 61
- BLOAD ................................. 61
- INP and OUT ........................... 62
- INPUT and LINE INPUT .................. 62
- STORE and RECALL ...................... 62
- FILESELECT ............................ 63
-
- 12. MIDI
- INPMID$ ............................... 67
- INP ................................... 67
- Midi-commands ......................... 67
-
- 13. MODEM
- INPAUX$ ............................... 70
- INP ................................... 70
- Rsconf (XBIOS 15)...................... 70
-
- 14. MOUSE
- Editor ................................ 71
- Fileselector .......................... 71
- MOUSE ................................. 71
- SETMOUSE .............................. 71
- DEFMOUSE .............................. 72
-
- 15. JOYSTICK
- STRIG and STICK ....................... 74
-
- 16. SOUND
- SOUND and WAVE ........................ 75
- Dosound (XBIOS 32) .................... 75
- Samples ............................... 76
- Speech ................................ 77
- Soundmachine .......................... 77
-
- 17. PROGRAM DECISIONS
- IF ... ENDIF .......................... 78
- SELECT ................................ 78
-
- 18. PROGRAM LOOPS
- Calculations .......................... 79
- FOR ... NEXT .......................... 79
- Loops ................................. 80
-
- 19. PROGRAM CONTROL
- GOSUB ................................. 82
- ON BREAK GOSUB ........................ 82
- ERROR ................................. 82
- EVERY and AFTER ....................... 82
- GOTO .................................. 82
- DELAY ................................. 83
- CHAIN ................................. 83
- EXEC .................................. 83
-
- 20. GRAPHICS
- SETCOLOR and VSETCOLOR ................ 84
- Palette ............................... 84
- DEFMARK ............................... 87
- DEFFILL ............................... 87
- DEFLINE ............................... 89
- DEFTEXT ............................... 89
- GRAPHMODE ............................. 90
- PLOT and DRAW ......................... 91
- PCIRCLE ............................... 92
- CURVE ................................. 92
- TEXT .................................. 92
- SPRITE ................................ 93
- VQT_EXTENT ............................ 95
- Line-A ................................ 95
- HLINE ................................. 96
- ACHAR and ATEXT ....................... 96
- GET and PUT ........................... 96
- Degas-Pictures ........................ 97
- Neochrome-Pictures .................... 98
- VSYNC ................................. 98
- Scroll ................................ 98
- ACLIP ................................. 99
- Blitter ............................... 99
-
- 21. EVENTS
- MENU() ................................ 101
- ON MENU BUTTON ........................ 101
- ON MENU IBOX .......................... 102
-
- 22. PULLDOWN MENU
- OPENW 0 ............................... 103
- Desk-submenu .......................... 103
- File-submenu .......................... 103
-
- 23. WINDOWS
- GFA-windows ........................... 104
- CLOSEW ................................ 104
- TITLEW ................................ 105
- CLEARW ................................ 105
-
- 24. AES-LIBRARY
- ALERT ................................. 106
- SHEL_GET and SHEL_PUT ................. 106
-
- 25. GFAXPERT-FILES
- GFAXPERT.DOC .......................... 108
- GFAXPERT.LIB .......................... 108
- INLINE ................................ 108
- STANxxxx.LST .......................... 108
- START ................................. 112
- small print ........................... 113
-
- EPILOGUE .............................. 114
-
- INDEX ................................. 115
-
-
- INTRODUCTION
-
-
- Right now you are reading the second edition of the text GFAXPERT.DOC.
- This text is not meant to be a replacement of your GFA-manual. On the
- contrary, I assume you are already familiar with the GFA-manual and now
- want to know everything about GFA-Basic 3.0 that is not described properly
- in the manual.
-
- This text is about the (hidden) power of GFA-Basic 3.0. You will find
- nothing about version 3.5, apart from this sentence. And this sentence,
- because I would like to mention that I don't understand why GFA launched
- version 3.5. GFA-Basic is becoming far too expensive.
-
- All remarks in this text, especially about bugs, are based on GFA-Basic
- 3.07. I still hope version 3.08 will become available (how naive...),
- otherwise I'll have to wait for version 4. Not version 4.00 of course,
- because I know there will be at least 200 bugs in the first release.
-
- I wrote this text because I was disappointed by the contents of most books
- about GFA-Basic 3.0. Some authors use page after page to describe a boring
- program. Others delve deeply into menu's, windows and RSC, but ignore the
- "regular" Basic-commands. Instead of complaining, I decided to write the
- book that I would really like to see myself. Here it is. Forget all other
- books about GFA-Basic, you need only two things: your GFA-manual and this
- text. And to be honest, perhaps a good book about the AES-library, because
- you won't find much about that subject in this text.
-
- In this text you will find quite a few Procedures. Most Procedures that
- are listed (or mentioned) in this text can be found in one of the LST-
- files in the folder GFAXPERT.LIB. Downloaders should look for the file
- GFAXPRT2.ARC.
-
- I strongly advise you to read the chapter 'GFAXPERT-FILES' thoroughly,
- before you try to use the Procedure-library GFAXPERT.LIB. Especially note
- the following :
- (1) word-variables are the default
- (2) a couple of variables are declared as Standard Globals
- (3) some Standard Functions are defined
- (4) a few Standard Procedures are present
- (5) the Standard Array color.index() is declared
- A Procedure could use any of the Standard Globals, Functions, Procedures
- or the Standard Array. I usually mention this in comment-lines in the
- Procedure. If you Merge such a Procedure into an existing program, you
- will have to adapt your program or the Procedure.
-
- I still believe in GFA-Basic 3.0. And I also believe in sharing ideas,
- Procedures and programs with other users, starting with you. If you feel
- guilty about receiving all these goodies for (almost) nothing, you will
- find a free consult in the chapter 'EPILOGUE'.
-
- I could only write this text because many GFA-users shared their
- experience with others. I dedicate this text to them. Special thanks to
- everyone who pointed out bugs, mistakes and omissions in the first edition
- of GFAXPERT.DOC. All mistakes in the second edition are made by
-
-
- Han Kempen
-
-
- 1. GENERAL
-
-
- Start-up
-
- Programs in an AUTO-folder are executed automatically after a reset. The
- interpreter GFABASIC.PRG is a GEM-program, and cannot be started in this
- way. With TOS 1.4 you can install a GEM-program as auto-booting. With
- older TOS-versions you could use a program like HEADSTRT.PRG in your AUTO-
- folder to start GFABASIC.PRG automatically. You can't start a GFA-program
- this way (I think).
-
- If you have written a (compiled) program that can be run either from the
- AUTO-folder or from the desktop, you can determine which is the case :
- IF PEEK(&H2C+4)=0 ! 4th byte of Line-F vector
- (...) ! AUTO
- ELSE
- (...) ! desktop
- ENDIF
-
- There are several ways to (re)start your computer. The obvious one is to
- switch the ST off, wait a few seconds (15 seconds with a 1040 ST!), and
- switch on again. This is called a "cold" or "hard" reset. Your computer
- suffers a little, and it takes some time. If you use the reset-button on
- your ST, you perform a "warm" or "soft" reset. The operating system
- automatically performs a warm reset if you switch between Low and Medium
- resolution on the desktop. If you suspect a program of changing system
- variables, you should always use a cold reset. After a warm reset the
- system variables in low memory are not initialised again. Garbage will
- stay there and will undoubtedly lead to interesting effects. You can
- perform both a warm and a cold reset from GFA-Basic with the following
- Procedures :
- PROCEDURE coldstart
- SLPOKE &H420,0
- SLPOKE &H426,0 ! probably not necessary
- SLPOKE &H43A,0
- ~XBIOS(38,L:LPEEK(4))
- RETURN
- '
- PROCEDURE warmstart
- ~XBIOS(38,L:LPEEK(4))
- RETURN
-
- If you would like to boot from your second (external) drive B, try :
- SLPOKE &H446,1 ! boot from drive B after next reset
- @warmstart
-
-
- Application
-
- It is convenient to install the extension GFA as an application for
- GFABASIC.PRG. Click once on GFABASIC.PRG and choose Install Application
- from the Options-menu. Type GFA as Document Type, click on OK and save the
- desktop. If you double-click a GFA-program (extension .GFA) from the
- desktop, GFABASIC.PRG is automatically loaded first. Choosing Install
- Application you will only see the most recently installed application. Use
- a disk-editor to examine the file DESKTOP.INF and you will find all
- installed applications (look for #G). You could also use the method
- described in the paragraph 'SHEL_GET and SHEL_PUT', or the RECALL-method
- from the paragraph 'STORE and RECALL'.
-
-
- Monitor
-
- The Atari colour monitor SC1224 works with a vertical frequency of either
- 50 Hz or 60 Hz :
- SPOKE &HFF820A,254 ! 50 Hz
- SPOKE &HFF820A,252 ! 60 Hz
- For 60 Hz, bit 1 of the Sync Mode Register is cleared. Don't change bit 0,
- or the video controller chip will not use the so-called sync pulses. After
- a reset, the operating system defaults to 50 Hz. The screen is a little
- larger than at 60 Hz, but the screen flickers slightly. If you connect
- your ST to a TV through a modulator, you should use 50 Hz. Otherwise you
- are advised to use 60 Hz.
-
-
- Break
-
- It's not easy to find in the GFA-manual: you can stop a running program by
- pressing <Control> <Left Shift> <Alternate> simultaneously. But if you're
- reading this text, you know this already. It's impossible to interrupt a
- program during DELAY! Study the Standard Procedure Break in one of the
- STANxxxx.LST-files to see how I react after a 'Break'.
-
-
- Operating System
-
- If you program in a language like GFA-Basic, you won't notice much of the
- actual workhorse inside your ST-computer: The Operating System (TOS). But
- even GFA-Basic does not have a Basic equivalent for all TOS-functions,
- although you can use almost all functions from GFA-Basic.
-
- TOS can be divided in two main parts: (GEM)DOS and GEM. The first is a
- collection of "lower level" routines for communication with keyboard,
- screen, printer, etc. In GFA-Basic you can call these routines with the
- commands BIOS, XBIOS and GEMDOS. The Graphics Environment Manager (GEM)
- consists of two collections of routines: the VDI (Virtual Device
- Interface) and the AES (Application Environment Services). The VDI takes
- care of regular graphics and should have included GDOS. Atari didn't
- include GDOS in the VDI, so you have to load it if you need it. Most VDI-
- functions have a Basic equivalent in GFA. The AES takes care of the
- communication with the user through menu, Alert-box, window, etc. Most
- AES-functions can be accessed through the AES-library in GFA-Basic 3.0.
-
- With GEMDOS-function 48 (Sversion) you can find the version of your
- GEMDOS. For both the old TOS and the Blitter-TOS &H1300 (version 0.19) is
- returned. The French Turbo-DOS has version 0.20 and the new Rainbow TOS of
- 1988 has version 0.21.
- Another way to find out the version of TOS uses the system header of TOS
- (not necessarily located in ROM!) :
- adr%=LPEEK(&H4F2)
- version$=HEX$(DPEEK(adr%+2))
- The good old ROM-TOS (1986, actually not so good) has version &H0100
- (1.0), the Mega-ST Blitter-TOS (1987) version &H0102 (1.2). And of course
- the new TOS ('Rainbow TOS') has version 1.4. You could also examine the
- date of your TOS-version :
- date$=HEX$(LPEEK(adr%+24))
- My ancient TOS 1.0 has '11201985' as the date.
-
-
- 2. THE EDITOR
-
-
- Abbreviated Commands
-
- The editor recognizes the following abbreviations (not a complete list) :
-
- ALINE - ALI FILESELECT- FILE POLYMARK - POLYM
- ARECT - AR FILL - FI PRINT - P or ?
- ARRAYFILL - ARR FUNCTION - FU PROCEDURE - PRO
- ATEXT - AT GOSUB - G or @ PSET - PS
- BMOVE - B GRAPHMODE - GRA QUIT - Q
- BOUNDARY - BOU HIDEM - HI REPEAT - REP
- CASE - CA HLINE - HL RESTORE - RES
- CIRCLE - CI IF - I RETURN - RET
- CLOSE - CL INPUT - INP RSET - RS
- COLOR - C LINE - LI SELECT - S
- DATA - D LINE INPUT- LI SETCOLOR - SET
- DEFFILL - DEFF LOCAL - LOC SETMOUSE - SETM
- DEFLINE - DE LOOP - L SGET - SG
- DEFMARK - DEFMA LPRINT - LPR SHOWM - SH
- DEFMOUSE - DEFM LSET - LS SWAP - SW
- DEFTEXT - DEFT MID$(..)= - MI ..)= TEXT - T
- DELETE - DEL MOUSE - MOU UNTIL - U
- DRAW - DR NEXT - N VOID - V
- EDIT - ED OPEN - O VSYNC - VS
- ELLIPSE - ELL PAUSE - PA WAVE - WA
- ELSE - E PBOX - PB WEND - WE
- ENDFUNC - ENDF PCIRCLE - PC WHILE - W
- ENDIF - EN PELLIPSE - PE
- ENDSELECT - ENDS PLOT - PL
- ERASE - ERA POLYFILL - POLYF
- EXIT IF - EX POLYLINE - POL
-
- If the abbreviated command is followed by anything else, you have to
- insert a space (e.g. 'C 1'), except with '@' and '?' :
- @proc1
- G proc1
- '
- ?"hello"
- P "hello"
-
-
- Syntax
-
- The parser checks for correct syntax after you press <Return>. Many typo-
- bugs are prevented this way. The only disadvantage is that the parser
- recognizes some variables as commands. It's impossible to use the follo-
- wing names as the first word on a line: data_byte|, dirty$, double,
- printer$, file%, quit!. The last one is nasty, because the parser changes
- the line 'quit!=FALSE' into 'QUIT!=FALSE' without warning for a syntax-
- error. If you now run the program you will return to the desktop when QUIT
- is encountered. Of course you have not lost your valuable program, because
- you always Save before you Run. Do you really? If the parser refuses the
- name of a variable, you can use LET (e.g. 'LET quit!=FALSE'). But you will
- have to change the name if it is a label (e.g. the label 'data1:' could be
- changed into '1data:' or 'd.ata1:').
-
-
- Folded Procedures
-
- If you press <Control> <Help> on a Procedure-line, all Procedures follo-
- wing and including the current one are folded/unfolded. You can unfold all
- Procedures at once by putting the cursor on the first Procedure-line and
- pressing <Control> <Help>. I suggest you leave all Procedures in the
- Procedure-Library GFAXPERT.LIB folded, unless you want to examine a
- Procedure. The editor-commands 'Find' and 'Replace' will skip folded
- Procedures. Never change the Procedure-line of a folded Procedure, always
- unfold it first.
-
-
- Tab
-
- If you press <Tab>, the cursor jumps to the next tab-position, without
- altering the current line. If you use <Left Shift> <Tab>, the line is
- filled with spaces from the current cursor-position to the next tab-
- position. Pressing <Right Shift> <Tab> erases all consecutive spaces to
- the left of the current cursor-postition. If the current cursor-position
- happens to be a space, this space and all spaces to the right are erased
- as well.
-
-
- Cut and Paste
-
- If you press <Control> <P>, the current line from the cursor to the end of
- the line is cut, and saved in an internal buffer. <Control> <O> inserts
- the saved line at the current cursor-position. You can use this method to
- "cut and paste" a part of a line. Press <Control> <P>, then <Control> <O>
- to restore the original line. Move the cursor to the desired position and
- press <Control> <O>. Block-operations are only possible with complete
- lines.
-
-
- Load
-
- You can use Load only with *.GFA-files, not with ASCII-files (such as the
- *.LST-files). ST-Basic files are ASCII-files, so you can Merge them.
-
- More recent programs in GFA-Basic (from 3.04) cannot be loaded by earlier
- interpreters (up to 3.02). Of course you should have the most current
- version (at least version 3.07), but the following method should always
- work. Lengthen the program until you can load it successfully :
- OPEN "A",#1,file$
- PRINT #1,STRING$(1000,0)
- CLOSE #1
-
-
- Save
-
- After 'Save' (*.GFA-file) or 'Save,A' (*.LST-file) with an existing file,
- the old file is renamed with a BAK-extension. Nice precaution, but you
- should delete those *.BAK-files every now and then.
-
- If you kill and save files regularly, new files will be stored in a
- fragmented way. Loading a fragmented file takes more time than loading a
- file that occupies consecutive sectors on the disk. You can correct this
- as follows. First make a backup-disk (yes, you should already have one).
- Copy all files to a RAM-disk by clicking on the drive-icon and dragging it
- to the window of the destination drive. You can't use disk-copy (dragging
- drive-icon to drive-icon) because the destination-drive is a RAM-disk.
- Format the source-disk and copy all files back (this must be a file-copy,
- not a disk-copy). Now, all files are saved on consecutive sectors. You
- could speed up things a little bit more by copying the most-used files
- first. The drive-head now needs less time to reach these files.
-
- Don't try to 'Save,A' an existing file to a full disk. I have tried it
- once and lost both the original file (should have become a *.BAK-file) and
- of course the saved file. Also, the editor (or TOS) had erased the program
- from memory... Thank you.
-
-
- Llist
-
- There has been some confusion about the following point-commands for the
- printer :
- .p- - point-commands are not printed
- .p+ - point-commands are printed again
- .llxx - line-width
- .plxx - page-length
- .pa - form feed
- Sometimes the commands '.cp' and '.nu' are mentioned, but I don't know how
- to use these.
-
- You can only use one point-command in one line. I use the following lines
- for my printer (96 characters/line in Elite-mode) :
- .p-
- .n4
- .lr3
- .ll88
- Save this as LLIST.LST and Merge it after the last line of a program
- before choosing 'Llist'. The actual listing is then printed with 80
- characters/line, preceded by the line-numbers (4 characters + space). If
- your program is longer than 10000 lines, you should use '.n5', but in that
- case you probably don't have time to read this. A nice touch is the
- automatic execution of a form feed after printing the listing.
-
- If the listing contains special characters (ASCII-code < 32 or > 126),
- some of those characters might be interpreted as printer-commands. My
- printer switches to condensed printing after receiving the Atari-symbol.
- Installing the proper printer-driver (e.g. PTEPSON.PRG) will prevent that.
- But I never install a printer-driver because there are some serious
- disadvantages. Read more about it in the paragraph 'HARDCOPY'.
-
- You can stop the printing process by pressing the 'Break'-combination
- <Control> <Left Shift> <Alternate>, unless Break has been disabled with
- 'ON BREAK CONT'. Your printer will continue printing though, until its
- input-buffer is empty, or until you turn the printer off.
-
-
- Insert-mode
-
- If you return to the editor, you'll always be in Insert-mode, even if you
- left the editor in Overwrite-mode. By the way, the editor restores the
- original colour-palette, so you are not bothered by palette-changes in a
- program. In the old days I was sometimes caught by the dreaded phenomenon
- of black characters on a black background, but now you can always read the
- listing on your screen.
-
- By the second way, there is only one thing I don't like about the GFA-
- editor. It's not easy to merge a Procedure from a LST-file with the
- program you're working on. Save the program, clear memory with 'New',
- 'Merge' the LST-file, mark the Procedure as a block, save the block,
- 'Load' the original program, find the correct line and 'Merge' the saved
- block. A new command NMerge (New+Merge) would make the life of a GFA-
- programmer a little easier. A better idea would be the command BMerge
- (Block-Merge). Then I could choose this command, clip a Procedure-block,
- and the block would be inserted in the listing automatically. Are you
- reading this, Frank? If you are, how about a function for changing upper
- case into lower case. In the GFA-EDITOR I SOMETIMES (oops) forget I
- pressed CapsLock. And how about a function to clear a line from the cursor
- to the next space-character. And...
-
-
- Direct Mode
-
- Enter the Direct Mode by pressing <Esc> or <Shift> <F9> in the editor.
-
- In Direct Mode you can restore the previously used line with <Undo>. With
- <Up arrow> and <Down arrow> you can even recall up to 8 of the last used
- lines. Press <Insert> to switch between Insert-mode and Overwrite-mode. As
- usual <Esc> clears the line, but if you press <Esc> on an empty line, you
- will return to the editor immediately. You can also return to the editor
- with <Control> <Shift> <Alternate>, even without first clearing the
- command-line. You can call Procedures in your program from the Direct Mode
- (e.g. '@show'). If you (temporarily) merge some special Procedures with
- the program you are developing, you could use the Direct Mode as a Command
- Line Interpreter.
-
-
- DEFLIST
-
- The command 'DEFLIST n' only works in Direct Mode, not in a program. You
- can also choose 'Deflist' from the drop-down menu, after clicking on the
- Atari-symbol.
- Special Characters
-
- You can enter characters with ASCII-code 32-126 directly from the key-
- board. These characters are usually called ASCII-characters. The codes
- 0-31 and 127 are used as control-codes, but additionally special charac-
- ters have been assigned to these codes. The characters with code 128-255
- are sometimes called "extended ASCII-characters" and are partly identical
- to the IBM-characters with the same codes. I loosely use the expression
- "ASCII-code" for all codes 0-255.
-
- You can enter characters with code 0-31 or 127-255 by pressing <Alternate>
- and then entering the character code. Release the <Alternate>-key and the
- character appears on your screen. E.g., you could enter the Escape-
- character by holding <Alternate> down and pressing <2> and <7>. This is
- much faster than entering CHR$(27), but Llisting a file with Escape-
- characters is probably not a good idea (less important, 1st Word Plus
- could get confused too). Llisting CHR$(27) doesn't bother your printer at
- all. It's not possible to enter CHR$(10) or CHR$(13) with the 'Alternate'-
- way. You can enter the first by pressing <Control> <A> and then <1> <0>
- <Return>. For code 13 you have to use CHR$(13).
-
- Never use code 4 (EOT, visible as left arrow) in a LST-file. If you Merge
- a LST-file, the GFA-editor thinks the end of the file is reached at that
- point (&H04) and refuses to load anything following this code!
-
-
- 3. VARIABLES
-
-
- Variable-type
-
- In GFA-Basic we use the expressions 'Byte', 'Word' and 'Integer' for the
- three integer-variables. Because all three are integers, the expression
- 'Integer' for the 4-byte integer-variable is sligthly confusing. In other
- languages this variable is called 'Longword' or simply 'Long'. An address
- in RAM should always be a 4-byte integer.
-
-
- DEFWRD
-
- I prefer to declare word-variables as the default (for variables without
- postfix) with: DEFWRD "a-z"
-
- I recommend the use of word-variables (2 bytes) for two reasons. In
- calculations, the use of the special integer-operators (ADD, SUB, INC,
- etc.) speeds the program up considerably. If you insist on using the
- regular operators (+, -, etc.) you should use floating point variables
- instead. Using the regular operators, the interpreter has to convert
- integer-variables to floating point, does the calculation and converts the
- result back to integer again. That's why a#*b# is calculated faster than
- a&*b&. But MUL(a&,b&) is much faster than a#*b#. It takes some time to
- recognize what an expression like DIV(a,MUL(ADD(a,b),SUB(b,c))) means. I
- suggest you use the regular operators if the calculation-time is not
- critical. In loops, the gain in calculation time really counts, so you
- should use the integer-operators. That way you will learn Polish too. The
- second reason for using word-variables is, that in a compiled program
- calculations with word-integers are usually the fastest.
-
- IMPORTANT: if a number-variable has no postfix in this text, you should
- assume it's a word-variable. I'll use the postfix |, % or # where
- appropriate. Please note that the interpreter assumes a number-variable
- without postfix is a floating point variable, unless you use DEFWRD "a-z".
-
-
- Boolean
-
- The following five lines :
- IF number>0
- test!=TRUE
- ELSE
- test!=FALSE
- ENDIF
- can be shortened to just one line :
- test!=(number>0)
- This works, because the '>'-operator returns TRUE or FALSE (actually -1
- or 0).
-
- Another little trick :
- IF i=1
- n=n*2
- ELSE IF i=2
- n=n*5
- ELSE
- n=0
- ENDIF
- This could be shortened to :
- n = n*-2*(i=1) + n*-5*(i=2)
- The example is ridiculous, but the principle involved could be useful. The
- expressions 'i=1' and 'i=2' are either 0 (FALSE) or -1 (TRUE).
-
- It is not necessary to use something like :
- IF flag!=TRUE
- (...)
- ENDIF
- You can simply use :
- IF flag!
- (...)
- ENDIF
-
-
- Integer
-
- You can't assign 2^31 to a 4-byte integer-variable. Although an integer
- contains 32 bits, you can't use bit 31. This bit is a flag for a negative
- integer. The largest positive number you can assign to an integer-variable
- is therefore 2^31-1 (2147483647). I could have written an analogue
- paragraph about the 2-byte word-variables, but I didn't.
-
-
- Floating Point
-
- The range of floating point variables (postfix #) is :
- -1.0E1000 < x# < 1.0E1000
- Larger or smaller numbers can be used in calculations, but not printed,
- because the exponent may contain not more than 3 digits (1.0E1000 is
- displayed as 1.0E;00).
-
-
- VAR
-
- If you call a Procedure and use VAR (call by reference), all variables
- and/or arrays after VAR are called by reference. An example to clarify
- this :
- @test(10,5,number%,array%())
- (...)
- PROCEDURE test(a,b,VAR x%,y%())
- ' now a=10 and b=5 (call by value)
- ' number% and array%() can now be used as x% and y%()
- x%=a+b ! global variable number% is now 15
- ARRAYFILL y%(),1 ! all elements of array%() are now 1
- RETURN
- In prehistoric days you could have used SWAP, but VAR makes life easier :
- @test(*a%())
- (...)
- PROCEDURE test(ptr%)
- SWAP *ptr%,x%() ! array a%() temporarily renamed as x%()
- (...) ! do something with the array
- SWAP *ptr%,x%() ! restore pointer before leaving Procedure
- RETURN
-
-
- FUNCTION
-
- You can only leave a FUNCTION by RETURNing a value or a string. This
- value/string is usually assigned to a variable. If the FUNCTION returns a
- string, the function-name has to end with '$' :
- FUNCTION test
- RETURN 126
- ENDFUNC
- '
- FUNCTION test$
- RETURN "this is a string"
- ENDFUNC
-
-
- CLEAR
-
- Because CLEAR is automatically executed when you run a program, it's not
- necessary to start you program with this command.
-
-
- ERASE
-
- It's impossible to reDIMension an existing array. You first have to ERASE
- the existing array and then you can DIMension a new array. It is not
- necessary to test for the existence of an array with DIM?() before you use
- ERASE. In other words, you can use ERASE even if the array doesn't exist :
- ERASE array$() ! just in case this array already exists
- DIM array$(200)
-
- After ERASEing an array, GFA rearranges the remaining arrays. All arrays
- that have been DIMensioned after the deleted array are moved in order to
- fill the gap of the deleted array. This is important if you use V:array(0)
- in your program (read the paragraph 'RESERVE').
-
-
- DUMP
-
- Examine all variables in your program by typing 'DUMP' in Direct Mode.
- Press <CapsLock> to slow down the scrolling-speed, or press the right
- <Shift>-key to temporarily stop the scrolling. The Procedure Debug enables
- you to use DUMP during debugging. This is the best way to discover those
- nasty typo-bugs in a variable-name. You'll probably be surprised to see
- the names of deleted variables as well. Also, any variable-name you used
- in Direct Mode appears. All these names are SAVEd with the program! Delete
- all unwanted names as follows (a RAM-disk would be convenient) :
- - Load the file
- - Save,A (press <Return> in Fileselector)
- - New
- - Merge (press <Return> again)
- - Save (press <Return> once more)
- The file could be much shorter after this operation.
-
-
- TYPE
-
- The command TYPE does not seem to work properly if you use local
- variables. I don't know what's wrong.
-
-
- READ
-
- As a rule, I always RESTORE the appropriate label before READing DATA-
- lines. That way I can use DATA-lines in Procedures :
- PROCEDURE read.data
- RESTORE these.data
- (...) ! READ the DATA here
- these.data:
- DATA 1,2,3,4
- RETURN
-
-
- SWAP
-
- The 52 cards in bridge (or another card-game) can be represented by a
- byte-array. Fill the elements 1-52 of the array with the value 1-52. The
- values 1-13 would represent the Club-cards (2,3,4,...,Q,K,A), values
- 14-26 the Diamonds, values 27-39 the Hearts and values 40-52 the Spades.
- Shuffling the cards can now be simulated with the Procedure Shuffle :
- DIM deck|(52)
- FOR i=1 TO 52 ! ignore index 0
- deck|(i)=i
- NEXT i
- @shuffle(deck|())
- (...)
- PROCEDURE shuffle(VAR proc|())
- LOCAL i,j
- FOR i=DIM?(proc|())-1 DOWNTO 2
- j=RAND(i)+1
- SWAP proc|(j),proc|(i)
- NEXT i
- RETURN
-
-
- TIME$
-
- You can use TIME$ to print the current time on the screen. In the
- Procedure Time you'll find a way to print the time every second, although
- TIME$ is updated every two seconds :
- PROCEDURE time
- ' *** activate with : EVERY 200 GOSUB time
- ' *** global : TIMER$
- LOCAL t$
- t$=TIME$
- IF t$=timer$
- MID$(timer$,8)=SUCC(RIGHT$(timer$))
- ELSE
- timer$=t$
- ENDIF
- PRINT AT(1,1);timer$
- RETURN
-
-
- TIMER
-
- If you need a stopwatch, you can use the following Procedures :
- PROCEDURE stopwatch
- ' *** global : STOP.SECONDS# STOP.H STOP.M STOP.S WATCH.ON!
- LOCAL s#
- IF watch.on!
- stop.watch#=TIMER
- stop.seconds#=(stop.watch#-start.watch#)/200
- stop.h=stop.seconds#/3600
- s#=stop.seconds#-stop.h*3600
- stop.m=s#/60
- stop.s=s#-stop.m*60
- watch.on!=FALSE
- ELSE
- watch.on!=TRUE
- start.watch#=TIMER
- ENDIF
- RETURN
- '
- PROCEDURE print.stopwatch
- IF stop.h>0
- PRINT stop.h;" h ";stop.m;" m";
- ELSE
- IF stop.m>0
- PRINT stop.m;" m ";stop.s;" s";
- ELSE
- IF stop.seconds#>=10
- PRINT USING "##.# s",stop.seconds#;
- ELSE
- PRINT USING "#.## s",stop.seconds#;
- ENDIF
- ENDIF
- ENDIF
- RETURN
- You start the stopwatch by calling the Procedure Stopwatch. Calling this
- Procedure again will stop the stopwatch. Then you can PRINT the elapsed
- time at the current cursor-position with the Procedure Print.stopwatch, or
- you could use one of the Global Variables from the Procedure Stopwatch to
- do something else.
-
-
- DATE$
-
- Find the day of the week with the Procedure Day.of.week :
- PROCEDURE day.of.week(day.date$,VAR day$)
- LOCAL day,mp,month,year,m,h,w,week$,n
- day=VAL(LEFT$(day.date$,2))
- mp=INSTR(day.date$,".")
- month=VAL(MID$(day.date$,mp+1,2))
- year=VAL(RIGHT$(day.date$,4))
- IF month<=2
- m=10+month
- year=year-1
- ELSE
- m=month-2
- ENDIF
- h=year/100
- y=year-100*h
- w=(TRUNC(2.6*m-0.2)+day+y+TRUNC(y/4)+TRUNC(h/4)-2*h) MOD 7
- RESTORE weekdays
- FOR n=0 TO w
- READ day$
- NEXT n
- '
- weekdays:
- DATA Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday
- RETURN
- This Procedure uses Zeller's Congruence to determine the day of the week.
-
-
- 4. MEMORY
-
-
- RAM
-
- An overview of the memory of my 1040 ST (start at the bottom) :
- address
- &H FFFFF top of memory of 1040 ST (1024 K)
- &H FFD00 767 unused (?) bytes
- XBIOS(2) = &H F8000 screen memory (32000 bytes)
- HIMEM = &H F4000 16384 unused bytes (MALLOC(-1))
- &H ..... free memory (length FRE(0) bytes)
- &H 388EA program + variables (length varies)
- &H 10C2E GFA-Basic 3.07 interpreter
- BASEPAGE = &H 10B2E Basepage GFA-Basic (256 bytes)
- &H A100 start of available RAM
- &H 6100 global AES-variables
- &H 29B4 global BIOS- and GEMDOS-variables
- L~A = &H 293A Line A variables
- &H 93A local BIOS-variables + BIOS-stack
- &H 400 BIOS system-variables
- &H 0 exception vectors
-
- The BIOS system-variables (&H400 - &H4FF) are "cast in concrete" by Atari.
- Other (undocumented) variables in RAM should be avoided.
-
-
- INT{}
-
- You can use either INT{adr%} or WORD{adr%}. As you know, w=WORD{adr%} is
- faster than w=DPEEK(adr%), but you can't use WORD{} and the other related
- commands in supervisor mode. This means you can't access memory below
- address &H800. Of course you can PEEK/DPEEK/LPEEK everywhere (DPEEK and
- LPEEK on even addresses only), and you can use SPOKE/SDPOKE/SLPOKE to
- write in supervisor mode.
-
-
- RESERVE
-
- The command RESERVE can be used in three different ways :
- RESERVE n% : reserve n% bytes for GFA-Basic, release RAM up to HIMEM
- RESERVE -n% : reserve last n% bytes of RAM up to HIMEM
- RESERVE : restore to original
- The second command is my favourite. You must use a multiple of 256 with
- RESERVE. After 'RESERVE -400', only 256 bytes are released to GEMDOS. In
- this case you would have to use 'RESERVE -512', although you need only 400
- bytes! Use the Function Multiple if arithmetic is not your strongest
- point :
- RESERVE -@multiple(n%,256)
- Use 'RESERVE -n%' only once in your program. If you RESERVE memory a
- second time with 'RESERVE -m%', GFA releases m% bytes, not n%+m%.
-
- The command RESERVE (restore) does not always function properly. Especial-
- ly after EXEC 3 it's often impossible to restore the memory. I suspect
- this has something to do with the use of the malloc-function by the
- operating system. You could try the following :
- RESERVE -n% ! reserve as much as needed (multiple of 256)
- base%=EXEC(3,...) ! load, but don't start
- (...)
- ~MFREE(HIMEM) ! memory above GFA-Basic
- ~MFREE(base%) ! memory from Basepage of loaded program
- RESERVE ! hope it works now
- Don't be surprised by hang-ups or bombs after this operation...
-
- There are several ways to reserve a part of memory for special purposes
- such as music, pictures or other programs. E.g., you could use a string-
- variable to store a complete screen or a GET-picture. Don't use strings if
- garbage collection is a serious risk. If a large array is declared, the
- interpreter sometimes moves the strings in memory to create space for the
- new array. If you assign a new string to an existing string-variable, the
- old string is not erased. During garbage collection all unused strings are
- deleted and the active strings are rearranged. This means the address of a
- string (accessed through VARPTR or V:) is not fixed. That's not important
- for a GET-picture, because 'PUT x,y,pic$' still works all right. But if
- you swap screens with ~XBIOS(5,L:adr%,-1,-1), or call a routine with
- ~C:adr%(...), garbage collection will be fatal. One solution is not to use
- a variable for the address, but to use VARPTR or V:. A different approach
- would be the use of a byte-array :
- OPEN "I",#1,file$
- LET bytes%=LOF(#1) ! how much space is needed?
- CLOSE #1
- DIM assembler|(bytes%-1) ! create space for assembler-routine
- adr%=V:assembler|(0)
- BLOAD file$,adr% ! load the routine
- You can use the variable adr% safely, because a garbage collection has no
- influence on arrays. However, after ERASEing an array, all arrays that
- have been DIMensioned after the deleted array are moved in memory. So the
- array-method is not reliable either, unless you are certain that ERASE
- will not be used after you have determined the address of the byte-array.
- Another solution would be to declare the byte-array early in your program,
- so it will not be moved after ERASE. The only complete safe way is the use
- of INLINE or MALLOC.
-
-
- INLINE
-
- Use D (=DUMP) to dump an Inline-file in Hex-code to the printer.
-
- Don't use 'Save,A', because you will lose the Inline-code. You can't use
- INLINE in LST-files. If you would like to use INLINE in combination with a
- LST-file you could proceed as follows. First, create an INLINE-folder in
- the main directory and SAVE the Inline-code as a file (extension INL) in
- this folder. Merge the LST-file in your program and load the Inline-code
- in the INLINE-line. The program should be saved with 'Save'.
-
- The only limitation with INLINE is the maximum length of 32746 bytes. If
- you need more space, you have to use MALLOC.
-
- If you change the length of an existing INLINE-line, the editor sometimes
- erases a few lines from your program. It's safer to completely delete the
- old INLINE-line and then enter the new INLINE-line.
-
-
- MALLOC
-
- This is how you could use MALLOC :
- unused%=MALLOC(-1) ! "unused" memory above HIMEM (used by GEM)
- RESERVE -n% ! release last n% bytes to GEMDOS
- max%=MALLOC(-1)
- IF max%<>0
- adr%=MALLOC(max%-unused%) ! n% bytes now available to GFA-Basic
- ELSE
- ' error
- ENDIF
- (...) ! do something interesting
- ~MFREE(adr%) ! give back to GEMDOS...
- RESERVE ! and back to GFA-Basic
- Atari recommends you leave at least 8K to GEM, so you can't go wrong if
- you leave 16384 bytes to GEM (see paragraph 'RAM').
-
- Do not use MALLOC to allocate a lot of small memory-blocks, as GEMDOS will
- get confused. This problem is related to the "40-folder limit", because
- MALLOC uses the same buffer that is used to store information about a
- folder (see paragraph 'FILESELECT'). Allocate one large area and split it
- up in as many parts as you need. Also consider the use of INLINE, strings
- or byte-arrays instead of using MALLOC (read the paragraph 'RESERVE'). Do
- not use MALLOC in an accessory, or the allocated memory may be lost if the
- user changes the resolution.
-
- MALLOC(-1) returns the size of the largest available memory-block. Expect
- problems if another program has allocated a couple of separate memory-
- blocks to GEMDOS. In that case you would have to use MALLOC(-1) again,
- until a returned value of '0' indicates there are no more memory-blocks
- available.
-
-
- 5. SORT
-
-
- QSORT v. SSORT
-
- QSORT is faster than SSORT, unless the array is almost sorted already. I
- understand QSORT uses the recursive Quick-sort method, so you need more
- memory than with SSORT (iterative Shell-sort). Sort-freaks can study the
- Procedures Quick.sort.int and Shell.sort.int to see how the Quick-sort and
- Shell-sort can be implemented with ordinary GFA-Basic commands (like that
- dance: Quick, Shell, slow).
-
-
- QSORT of number-arrays
-
- Number-arrays can be QSORTed in three different ways :
- QSORT x%() - sorts array ; also with x|(), x&() or x#()
- QSORT x%(),n - sorts elements 0 through n-1
- QSORT x%(),n,y%() - elements of y%() are swapped too
- In all cases x%(-1) results in sorting in decreasing order.
-
- The third method is interesting if you need a sorted output, but don't
- want to change the original array. You can accomplish this as follows :
- - copy x%() to temporary array temp%()
- - determine index of last element : last=DIM?(temp%())-1
- - create index array : DIM index%(last)
- - fill index-array with index 0 through last
- - sort array : QSORT temp%(),last+1,index%()
- - ERASE temp%()
- The index-array must be an integer-array (postfix %). Also, the number of
- elements is not optional if you sort with an index-array. You can now
- print the numbers in array x%() in increasing order :
- FOR i=0 TO last
- PRINT x%(index%(i))
- NEXT i
-
- I have never seen the correct syntax for QSORT in print, so here it is :
- QSORT x([s])[,n[,y%()]]
-
-
- QSORT of string-arrays
-
- A string-array can be sorted in the same three ways as described for
- number-arrays. If you have created an index-array with last_name$(), you
- could print an alphabetical list :
- FOR i=0 TO last
- PRINT first_name$(index%(i))'last_name$(index%(i))
- NEXT i
-
- There are two extra possibilities with string-arrays.
-
-
- For the first possibility, create a byte-array and fill with appropriate
- ASCII-values :
- DIM ascii|(255)
- ARRAYFILL ascii|(),32 ! CHR$(32) is the space-character
- FOR i=48 TO 57
- ascii|(i)=i ! 0 - 9
- NEXT i
- FOR i=65 TO 90
- ascii|(i)=i ! A - Z
- NEXT i
- FOR i=97 TO 122
- ascii|(i)=SUB(i,32) ! a - z converted to A - Z
- NEXT i
- All characters that are not numbers or letters will be treated as a space
- (ASCII-value 32). Use the array ascii|() for sorting a string-array :
- QSORT x$() WITH ascii|()
- Now 'Atari' and 'ATARI' are treated exactly the same, because the
- interpreter uses the array ascii|() to convert lower case letters tempora-
- rily to upper case before sorting. You can even treat the international
- characters (ASCII-values > 127) correctly, e.g. ascii|(129)=85. Use a few
- DATA-lines to add the correct ASCII-value, like this :
- DATA 128,67,129,85,130,69
- You can combine this method with an index-array as well. The correct
- syntax is :
- QSORT x$([s]) WITH b|() [,n[y%()]]
- If you have done your homework, you should now be able to write a clever
- alphabetical sorting-program yourself. You wanted to become an expert,
- didn't you? Compare your program with the Procedures Ascii.qsort and
- String.index.qsort :
- PROCEDURE ascii.qsort(VAR txt$())
- IF DIM?(ascii|())=0
- @initio.ascii.array
- ENDIF
- QSORT txt$() WITH ascii|()
- RETURN
- '
- PROCEDURE initio.ascii.array
- LOCAL i,code1,code2
- DIM ascii|(255)
- ARRAYFILL ascii(),32 ! fill with space-character
- FOR i=48 TO 57
- ascii|(i)=i ! 0 - 9
- NEXT i
- FOR i=65 TO 90
- ascii|(i)=i ! A - Z
- NEXT i
- FOR i=97 TO 122
- ascii|(i)=SUB(i,32) ! a - z, converted to A - Z
- NEXT i
- RESTORE ascii.data
- REPEAT
- READ code1,code2
- ascii|(code1)=code2
- UNTIL code1=0
- '
- ascii.data:
- ' *** format : ASCII-code,replacement
- DATA 128,67,129,85,130,69,131,65,132,65,133,65,134,65,135,67
- DATA 136,69,137,69,138,69,139,73,140,73,141,73,142,65,143,65
- DATA 144,69,145,65,146,65,147,79,148,79,149,79,150,85,151,85
- DATA 152,121,153,79,154,85,155,67,158,83,160,65,161,73,162,79
- DATA 163,85,164,78,165,78,166,65,167,79,176,65,177,79,178,79
- DATA 179,79,180,79,181,79,182,65,183,65,184,79,192,121,193,121
- DATA 225,83,0,0
- RETURN
- '
- PROCEDURE string.index.qsort(switch!,VAR txt$(),index%())
- ' *** the index-array has to exist already
- ' *** if switch!=TRUE, array ascii|() is used
- LOCAL last,i
- last=DIM?(txt$())-1 ! index of last element
- DIM temp$(last)
- FOR i=0 TO last
- temp$(i)=txt$(i)
- NEXT i
- FOR i=0 TO last
- index%(i)=i
- NEXT i
- IF switch!
- IF DIM?(ascii|())=0
- @initio.ascii.array
- ENDIF
- QSORT temp$() WITH ascii|(),last+1,index%()
- ELSE
- QSORT temp$(),last+1,index%()
- ENDIF
- ERASE temp$()
- RETURN
-
- The second extra possibility with string-arrays is the use of 'OFFSET o'
- to ignore the first 'o' characters during sorting. Suppose you have
- created an array files$() with FILES and would like to sort the files by
- length :
- QSORT files$() OFFSET 13,n
- The first character (either a space or '*') and the filename (the next 12
- characters) are now ignored during sorting.
-
-
- 6. OPERATORS and NUMERICAL FUNCTIONS
-
-
- \
-
- The operator '\' (backslash) is identical to DIV :
- a=b\c
- Integer-division is not as useful as the other integer-operations, because
- the result is an integer. Of course it is, but this can easily result in
- large rounding errors.
-
-
- PRED and SUCC
-
- PRED(i) is faster than i-1 and SUCC(i) is faster than i+1. Both functions
- can also be used with strings. Note the clever use (ahem) of SUCC in the
- following line from the Procedure Time :
- MID$(timer$,8)=SUCC(RIGHT$(timer$))
- The rightmost digit of timer$ (always even) is increased with one.
-
-
- MOD
-
- If you use a counter in a loop in order to do something every time the
- counter reaches a multiple of 10, you could do this as follows :
- IF counter MOD 10=0 ! multiple of 10?
- (...) ! yes, do something
- ENDIF
- You could also use :
- IF MOD(counter,10)=0
- (...)
- ENDIF
-
-
- BCLR
-
- In GFA-Basic version 2.x you used AND to clear a bit :
- x|=x| AND &X11111011 ! clear bit 2 of this byte
- Remember, the first (rightmost) bit is bit 0, so a byte contains bit 0-7
- from right to left. In GFA-Basic 3.0 you clear a bit simply with :
- x|=BCLR(x|,2) ! clear bit 2 of this byte
- But if you want to clear more than one bit, you should use the AND-method:
- x|=x| AND &X11110000 ! clear bit 0-3 of this byte
- In this case you use a so-called mask to clear certain bits. You can use
- AND also as a function :
- y|=AND(x|,&X11110000) ! even faster than previous example
- This way you can test if a bit-mask "fits" a variable :
- IF AND(x|,mask|)
- (...)
- ENDIF
- An example of this method :
- IF AND(BIOS(11,-1),&X1001)
- (...) ! user pressed <Alternate> + right <Shift>
- ENDIF
- BSET
-
- In GFA-Basic 2.x you needed OR to set a bit, but now you use BSET :
- x|=BSET(x|,1)
- You still need the OR-method if you want to set more than one bit fast :
- x|=x| OR &X1010 ! set bit 1 and 3
- The mask &X1010 is used to set bits 1 and 3. Compare this with the AND-
- method, where 0 is used to clear a bit, while here 1 is used to set a bit.
- You can use OR not only as an operator, but also as a function :
- y|=OR(x|,&X1010)
-
-
- BCHG
-
- Instead of BCHG you should use the XOR-method if you want to change more
- than one bit (with a mask) :
- x|=x| XOR &X1110 ! change bit 1-3
- XOR can be used as a function as well.
-
-
- LOG
-
- Logarithms with a base other than 10 or e are computed as follows :
- LOG(x)/LOG(base)
-
-
- SINQ and COSQ
-
- If you are going to convert SIN (or COS) into SINQ (COSQ), you'll have to
- change from radials to degrees. For example, you would convert SIN(x) to
- SINQ(DEG(x)). Although SINQ is about five times faster than SIN, this
- extra computation makes the difference a little less spectacular. If you
- are lucky, the variable already is in degrees, so you can use SINQ
- immediately. SINQ and COSQ should not be used if you need very accurate
- results, only if you plot the result and are not going to use it for
- further computations. Examine the difference between the use of SIN/COS
- and SINQ/COSQ to see if the less accurate result is acceptable. In High
- resolution try something like this :
- fac#2*PI/639
- DRAW 0,200
- FOR x=0 TO 639
- y#=SIN(x*fac#)
- DRAW TO x,200+y#*200
- NEXT x
- ~INP(2)
- CLS
- '
- DRAW 0,200
- FOR x=0 TO 639
- y#=SINQ(DEG(x*fac#))
- DRAW TO x,200+y#*200
- NEXT x
- ~INP(2)
- CLS
- '
- fac#=360/639
- DRAW 0,200
- FOR x=0 TO 639
- y#=SINQ(x*fac#)
- DRAW TO x,200+y#*200
- NEXT x
- ~INP(2)
-
-
- EQV
-
- EQV doesn't work properly. EQV(0,-1) should be 0, but equals -65536. The
- bits 16-31 are always set: EQV seems to look at the bits 0-15 only.
-
-
- CARD and SWAP
-
- If a 4-byte integer (postfix %) consists of two words, you can extract
- these with :
- low.word=CARD(x%)
- high.word=CARD(SWAP(x%))
- Both words are interpreted as positive numbers.
-
- Unfortunately, there is no analogue function to swap the low and high
- byte of a word. That would be useful if you want to convert a word
- into/from Intel-format (MS-DOS). Rotating 8 bits should do the trick :
- FUNCTION intel.word(x%)
- RETURN CARD(ROR&(x%,8)) ! swap low/high byte
- ENDFUNC
- Now you should be able to extract the low and high byte of a word :
- low.byte|=BYTE(x)
- high.byte|=BYTE(@intel.word(x))
-
-
- MAX
-
- This is how you could find the highest value in a word-array :
- PROCEDURE max.array(VAR proc(),high)
- ' *** return highest value of array proc()
- LOCAL last,n
- last=DIM?(proc())-1
- high=proc(1) ! proc(0) ignored
- FOR n=2 TO last
- high=MAX(high,proc(n))
- NEXT n
- RETURN
- I often store special information in the element with index 0.
-
-
- Correlation
-
- Use the Procedure Correlate to determine the correlation between two
- arrays.
- 7. STRINGS
-
-
- INSTR
-
- The command INSTR(a$,b$,i) always returns '1' if a$=b$. For i=1 that's
- fine, but not for i>1. Don't blame me, I'm just the messenger.
-
-
- LSET and RSET
-
- If you use LSET or RSET, the string is padded with spaces :
- a$=" 345"
- LSET a$="12"
- PRINT a$ ! the interpreter prints "12 ", not "12345"
-
- You can use RSET for right justification of columns :
- f$=SPACE$(10)
- FOR i=1 TO 10
- RSET f$=text$(i)
- PRINT f$
- NEXT i
-
-
- Parser
-
- Parsing a string, you will frequently have to split the string into the
- target$, the string before and the string after that target$. The
- following functions could be helpful :
- FUNCTION before$(source$,target$)
- ' *** returns part of source$ before target$
- ' *** returns complete source$ if no target$ found
- LOCAL p
- p=INSTR(source$,target$)
- IF p=0
- RETURN source$
- ELSE
- RETURN LEFT$(source$,p-1)
- ENDIF
- ENDFUNC
- '
- FUNCTION after$(source$,target$)
- ' *** returns part of source$ after target$
- ' *** returns nullstring if no target$ found
- LOCAL p
- p=INSTR(source$,target$)
- IF p=0
- RETURN ""
- ELSE
- RETURN MID$(source$,p+LEN(target$))
- ENDIF
- ENDFUNC
-
-
- 8. KEYBOARD INPUT
-
-
- INKEY$
-
- All keypresses are saved in the keyboard-buffer. If you don't want INKEY$
- to read an "old" key, you should first clear the buffer :
- REPEAT
- UNTIL INKEY$="" ! clear keyboard-buffer
- key$=""
- REPEAT
- key$=INKEY$ ! wait for new key
- UNTIL key$<>""
-
- In the following table you'll find a few useful decimal ASCII-codes you
- can use after 'key$=INKEY$'. In the third column the hexadecimal scan-code
- of the key is also mentioned (see paragraph 'KEYGET').
-
- key ASC(key$) scancode
- <Backspace> 8 &H0E
- <Tab> 9 &H0F
- <Return> and <Enter> 13 &H1C and &H72
- <Esc> 27 &H01
- <Delete> 127 &H53
-
- key ASC(RIGHT$(key$))
- <F1> 59 &H3B
- <F10> 68 &H44
- <Shift> <F1> 84 &H54
- <Shift> <F10> 93 &H5D
- <Help> 98 &H62
- <Undo> 97 &H61
- <Insert> 82 &H52
- <ClrHome> 71 &H47
- <Left arrow> 75 &H4B
- <Right arrow> 77 &H4D
- <Up arrow> 72 &H48
- <Down arrow> 80 &H50
-
- Keys in the second part of this table return a 2-byte value after INKEY$.
- You only need the low byte, the high byte is &H00. That's why a Standard
- Global like help$ is defined as 'CHR$(0)+CHR$(98)'. Then it's easy to
- check if <Help> was pressed :
- IF key$=help$
- (...) ! <Help>
- ENDIF
- Otherwise, you have to test as follows :
- IF ASC(RIGHT$(key$))=98
- (...) ! <Help>
- ENDIF
- However, read the paragraph 'KEYGET' for the ultimate keypress-processor.
-
- If you are just waiting for any keypress, you could use either of the
- following methods (clear the keyboard-buffer first) :
- ~INP(2) ! my favourite
- '
- KEYGET code% ! perhaps this is clearer in a listing
- '
- REPEAT ! a loop is also possible
- UNTIL LEN(INKEY$)
- The latter method is needed if you are waiting for any keypress or any
- mouse-click :
- REPEAT
- UNTIL LEN(INKEY$) OR MOUSEK
-
-
- INPUT
-
- If you don't want the question mark to appear after INPUT, use :
- LOCATE col,lin
- INPUT "",txt$
- The nullstring and the comma are essential. Most of the time you'll need
- something like :
- LOCATE col,lin
- INPUT "Enter your name : ",name$
- But if the instruction-line is not the same as the INPUT-line, use :
- PRINT AT(col1,lin1);"Enter your name :"
- LOCATE col2,lin2
- INPUT "",name$
-
- After INPUT, the user can press <Insert> to switch between Insert-mode and
- Overwrite-mode. I have not been able to discover how to input character-
- codes 0-31 after INPUT. It's not important anyway, but I read somewhere
- you could use <Alternate> for this purpose. The Alternate-method can be
- used for character-codes 128-255 (not 127). In the following table you'll
- find some important characters with the decimal ASCII-code :
-
- character ASCII-code character ASCII-code character ASCII-code
-
- á - 160 é - 130 à - 161
- à - 133 è - 138 ì - 141
- ä - 132 ë - 137 ï - 139
- â - 131 ê - 136 î - 140
-
- ó - 162 ú - 163 ÿ - 152
- ò - 149 ù - 151 ß - 158
- Ö - 148 ü - 129
- ô - 147 û - 150
-
- α - 224 ≡ - 240 ½ - 171
- β - 225 ± - 241 ¼ - 172
- δ - 235 ≥ - 242 ² - 253
- µ - 230 ≤ - 243
- π - 227 ÷ - 246
- τ - 231 ≈ - 247
-
- ¢ - 155 © - 189
- £ - 156 § - 221
- Æ’ - 159
- If you want to use one of these characters after INPUT, you should hold
- <Alternate> down, enter the code, and release <Alternate>. I hope your
- printer-driver could digest this table...
-
- You can use <Backspace>, <Delete>, <Left arrow> and <Right arrow> on an
- INPUT-line, but also :
- <Up arrow> - cursor to start of input-line
- <Down arrow> - cursor to end of line
- <Esc> - erase line
- The first two feel slightly unnatural, I would prefer it the other way: up
- to end, down to start.
-
- Both INPUT and LINE INPUT use a special cursor, so it doesn't make much
- sense to use XBIOS 21 (Curscon) to do something interesting with the TOS-
- cursor.
-
-
- INPUT$
-
- For the input of a secret password, you could use something like :
- PRINT "type password (5 characters) : ";
- code$=INPUT$(5)
- The password does not appear on the screen.
-
-
- LINE INPUT
-
- LINE INPUT uses the underscore (_) as the cursor in a window. After you
- press <Return>, the underscore is not completely erased. The rightmost
- pixel remains visible. I think this is a GEM-bug.
-
-
- KEYTEST
-
- The KEYTEST-function does not respond to keys such as <Help>, <Undo>, etc.
-
-
- KEYGET
-
- KEYGET waits for a keypress, just like INP(2). But KEYGET is far more
- flexible, because it returns the ASCII-code and the scan-code of any key
- and also the state of the special keys <Shift>, <Control>, <Alternate> and
- <CapsLock>. Consult your manual for tables of ASCII-codes and scan-codes
- (in the paragraph 'INKEY$' you already encountered some important codes).
- Study the following example to get an impression of the easy way you can
- examine all keypresses with KEYGET :
-
- @initio_keyget ! assign variables to the three codes
- '
- DO
- KEYGET get_code%
- @keyget ! process keypress there (not included)
- LOOP
- '
- PROCEDURE initio_keyget
- ABSOLUTE ascii|,V:get_code%+3
- ABSOLUTE scan|,V:get_code%+1
- ABSOLUTE status|,V:get_code%
- RETURN
-
- You will have to write your own Keyget-Procedure. You can check if any of
- the special keys has been pressed, by using BTST(status|,bit) :
- bit 0 = Right <Shift>
- bit 1 = Left <Shift>
- bit 2 = <Control>
- bit 3 = <Alternate>
- bit 4 = <CapsLock>
- You could discover if the user had pressed <Control> <Down arrow> with :
- IF scan|=&H50 AND BTST(status|,2)
- (...)
- ENDIF
-
- If you are only interested in monitoring the five special keys, you could
- use BIOS 11 (Kbshift) as well :
- status|=BIOS(11,-1)
- Use the same table as above to test if bit 0-4 is set.
-
- You are advised to clear the keyboard-buffer before leaving the Procedure
- Keyget.
-
- In most cases the scan-code of a key is the same, whether you pressed a
- special key simultaneously or not. But watch out for the following
- exceptions! For <Shift> <F1> to <Shift> <F10> the scan-codes &H54 to &H5D
- are returned (not &H3B to &H44). On an MS-DOS computer these codes are
- used for the keys F11 to F20. The combinations <Control> <Left Arrow>
- (&H73) and <Control> <Right Arrow> (&H74) also have special codes. Blame
- MS-DOS. The combinations <Alternate> <1> to <Alternate> <=> have the
- special codes &H78 to &H83. That's ALT1 to ALT= for MS-DOS.
-
-
- KEYLOOK
-
- According to an unconfirmed report, KEYLOOK does not function properly
- with the pre-Blitter TOS.
-
-
- KEYPRESS
-
- KEYPRESS uses the same 4-byte format as KEYGET: &Hccss00aa. In it you
- will recognize the ASCII-code (&Haa), the scan-code (&Hss) and the code
- for the special keys (&Hcc). If you want to simulate the pressing of a key
- in an Alert box, you will have to send both the ASCII-code and the scan-
- code. Use &H1C000D to simulate the pressing of <Return>. Or &H04620062 for
- <Control> <Help>, although that certainly won't help in an Alert box. If
- you don't need the scan-code (e.g. with INPUT), you can use just KEYPRESS
- &Haa.
-
-
- KEYDEF
-
- The editor always uses KEYPAD &X101110, so you will have to set bit 4
- yourself (e.g. KEYPAD &X10000) before you will be able to use KEYDEF in
- your program.
-
-
- Keyboard
-
- As far as I know, there are four different keyboards available : USA
- (QWERTY), English (QWERTY), German (QWERTZ) and French (AZERTY). The key
- with scan-code &H2B (to the right of <Return>) has a different ASCII-code
- in each version :
- version ASCII-code character
- USA &H5C (92) \
- English &H23 (35) #
- German &H7E (126) ~
- French &H40 (64) @
- You could use XBIOS 16 (Keytbl) to determine the keyboard-version :
- PROCEDURE keyboard.version
- SELECT PEEK(LPEEK(XBIOS(16,L:-1,L:-1,L:-1))+&H2B)
- CASE &H5C
- usa.keybrd!=TRUE
- CASE &H23
- english.keybrd!=TRUE
- CASE &H7E
- german.keybrd!=TRUE
- CASE &H40
- french.keybrd!=TRUE
- ENDSELECT
- RETURN
-
- You should take into account the differences between the keyboard-versions
- if you are writing a program that should run smoothly in any country.
-
- In the following table I have gathered all keys that have not the same
- meaning on the four keyboard-versions :
-
- scancode USA English German French
- &H0C - - ß )
- &H0D = = - '
- &H10 Q Q Q A
- &H11 W W W Z
- &H15 Y Y Z Y
- &H1A [ [ Ü [
- &H1B ] ] + ]
- &H1E A A A Q
- &H27 ; ; ö M
- &H28 ' ' Ä \
- &H29 ` ` # `
- &H2B \ # ~ @
- &H2C Z Z Y W
- &H32 M M M ,
- &H33 , , , ;
- &H34 . . . :
- &H35 / / - =
- &H60 none \ < <
-
- If you are going to use any scan-code from this table, you should be very
- careful. It's not nice to ask a German user to press <Y>, but test for
- scan-code &H15 in your program...
-
- If you insist on doing things the hard way, you can find the ASCII-value
- that is assigned to a key with XBIOS 16. Actually there are three tables:
- one for a normal keypress, one for a shifted key and one for a keypress
- with CapsLock on :
- keytbl%=LPEEK(XBIOS(16,L:-1,L:-1,L:-1))
- shift%=keytbl%+&H80
- capslock%=shift%+&H80
- Now you can find the ASCII-code for any scan-code (< &H80) :
- ascii=PEEK(keytbl%+scancode) ! normal key
- ascii=PEEK(shift%+scancode) ! shifted key
- ascii=PEEK(capslock%+scancode) ! CapsLock on
-
-
- Keyclick, Keyrepeat and CapsLock
-
- Normally, you need the Keyclick as an audible feedback. Sometimes you have
- to switch the Keyclick off, e.g. while an XBIOS 32 song is playing :
- PROCEDURE key.click(switch!)
- IF switch!
- SPOKE &H484,BSET(PEEK(&H484),0) ! keyclick on
- ELSE
- SPOKE &H484,BCLR(PEEK(&H484),0) ! keyclick off
- ENDIF
- RETURN
-
- If your program reacts slowly after a keypress, you probably have to
- switch the Keyrepeat temporarily off :
- PROCEDURE key.repeat(switch!)
- IF switch!
- SPOKE &H484,BSET(PEEK(&H484),1) ! key-repeat on
- ELSE
- SPOKE &H484,BCLR(PEEK(&H484),1) ! key-repeat off
- ENDIF
- RETURN
-
- You can switch CapsLock on or off with :
- PROCEDURE caps(switch!)
- IF switch!
- ~BIOS(11,BSET(BIOS(11,-1),4)) ! CapsLock on
- ELSE
- ~BIOS(11,BCLR(BIOS(11,-1),4)) ! CapsLock off
- ENDIF
- RETURN
-
-
-
- 9. SCREEN OUTPUT
-
-
- PRINT
-
- It is very important to know if PRINT will be used on the so-called TOS-
- screen (no windows opened), or in a window. TOS emulates the VT52-terminal
- of Digital Equipment, so if you PRINT on the TOS-screen, the VT52-codes
- will be interpreted as commands. But in a window these codes are printed
- as characters!
-
- In both High and Medium resolution you can PRINT 25 lines of 80
- characters, but in Low resolution it's 25 lines of 40 characters only.
-
- Normally you can't PRINT a character at position (80,25) in High or Medium
- resolution, or at (40,25) in Low resolution. Try the following :
- PRINT AT(80,25);"X";
- and you will see that a linefeed is executed automatically, in spite of
- the semicolon after "X". On the TOS-screen you can put a character at this
- position by using the VT52-command 'wrap off' :
- PRINT AT(80,25);"*wX"; ! use the Escape-character instead of *
- After 'Esc w' the linefeed is suppressed. The easiest way to enter the
- Escape-character in the GFA-editor is to hold <Alternate> down and then to
- enter <2> <7>. If you PRINT a string that doesn't fit on the current line,
- the remaining characters are either printed on the next line ('Esc v', the
- default in the interpreter, not in a compiled program), or discarded
- ('Esc w'). Actually, after 'Esc w' all characters up to the first CHR$(10)
- or CHR$(13) are discarded.
-
- It's impossible to PRINT characters with ASCII-code 0-31 on the TOS-
- screen. However, you can print any character with :
- OUT 5,code
- If necessary, use LOCATE first.
-
- After opening a window (OPENW x) the command DEFTEXT will change size and
- colour of PRINTed text as well! One advantage is that you can now PRINT in
- different colours on the screen.
-
- On the TOS-screen, all PRINTed text has the same colour. This colour is
- determined by colour-index 1 and is also used for the Alert-box and the
- Fileselector. The background on the screen is determined by colour-index
- 0. This colour is used after CLS.
-
- It is possible to PRINT in different colours on the TOS-screen, by using
- the VT52-code 'Esc b'. The background of PRINTed text can be changed with
- VT52-code 'Esc c'. Use the following functions to experiment :
- DEFFN ink$(color)=CHR$(27)+"b"+CHR$(color)
- DEFFN paper$(color)=CHR$(27)+"c"+CHR$(color)
- Use the colour-table from the paragraph 'SETCOLOR' or be prepared to
- become very frustrated. I use the Standard Array color.index() as the
- colour-table in my programs, so I change the colour of the PRINTed text or
- the back-ground with the Standard Functions :
- DEFFN ink$(color)=CHR$(27)+"b"+CHR$(color.index(color))
- DEFFN paper$(color)=CHR$(27)+"c"+CHR$(color.index(color))
- Remember, the VT52-codes have to be PRINTed to become effective, like
- this :
- PRINT @ink$(red);@paper$(green);" this text is eye-catching "
- Note the spaces at beginning and end of the string to emphasize the text-
- colour against the background-colour. Of course you have to declare the
- variables red and green first (usually colour-index 2 and 3; or if you
- don't use the VDI colour-index, try the numbers 1 and 2). I define the
- default colours as Standard Globals in my programs. Before I forget, it
- won't work in High resolution. Sorry, couldn't resist that one.
-
- In order to catch the eye of the user in High resolution you can PRINT
- reverse on the TOS-screen :
- PRINT "this is *p IMPORTANT *q" ! enter Esc instead of *
- Enter the Escape-character in the usual way. Note again the extra space
- both before and after the word that should stand out. Of course you could
- also use CHR$(27) :
- PRINT "this is ";CHR$(27);"p IMPORTANT ";CHR$(27);"q"
- More difficult to read on the screen, but easier to Llist. I use the
- Standard Function Rev$ in all programs :
- DEFFN rev$(txt$)=CHR$(27)+"p"+txt$+CHR$(27)+"q"
-
- If you use a comma with PRINT, the cursor will jump to the next tabulator-
- stop. Tab-stops are at position 1, 17, 33, 49 and 65. Try the following to
- see what I mean (in High or Medium resolution) :
- PRINT "1","17","33","49","65","1","17"
- If you use the comma after the last tab-stop, a linefeed is executed and
- the cursor jumps to the first tab-stop on the next line.
-
- The easiest way to use double quotes is by using double double quotes
- (read this twice to make sure you understand it) :
- PRINT "double quotes printed the ""easy"" way"
- In a DATA-line a single double quote suffices :
- DATA "look Ma, "double quotes" again"
- Or, simply :
- DATA look Ma, "double quotes" again
-
- Try the Procedure Fastprint in High resolution if you find PRINT too slow.
- This Procedure prints about four times faster! VT52-commands are ignored,
- because characters are copied straight from the font-table to the screen.
-
-
- LOCATE
-
- The syntax of PRINT AT and LOCATE is now less confusing :
- PRINT AT(column,line)
- LOCATE column,line
- In older versions of GFA-Basic it was LOCATE line,column. Check this if
- you run an old program and text is PRINTed on the wrong place.
-
-
- PRINT TAB
-
- PRINT TAB behaves strangely if the position is greater than 80. Try the
- following in High or Medium resolution :
- FOR i=0 TO 30
- PRINT TAB(i*20);i;
- NEXT i
- One way to solve this problem is :
- PRINT TAB(MOD(i*20,80));i; ! do use semicolons
- But I think this is a GFA-bug that probably will be corrected in future
- versions.
-
- You can combine TAB with PRINT AT and with PRINT USING :
- PRINT AT(1,1);"1";TAB(40);"40"
- PRINT TAB(40);USING "##",40
-
-
- Setscreen (XBIOS 5)
-
- With XBIOS 5 (Setscreen) it is possible to change the resolution from Low
- to Medium and from Medium to Low. Unfortunately, GEM ignores the switch,
- so GEM-commands (e.g. ALERT, TEXT, MOUSE) do not work properly! But you
- could change from Low to Medium resolution to show text on the TOS-screen
- with PRINT (and VT52-commands). Most users will be grateful for the
- improved readability of the text :
- ~XBIOS(5,L:-1,L:-1,1) ! switch from Low to Medium
- (...) ! print text in Medium resolution
- ~XBIOS(5,L:-1,L:-1,0) ! and go back to Low
- If you change the resolution, the VT52-emulator is automatically
- initialised. You'll probably have to adjust the palette before you can
- read the text without sun-glasses. Don't forget to save and restore the
- old palette.
-
- XBIOS 5 is very useful if you would like to draw on a screen before
- showing it to the user. Drawing on an "invisible" screen is indeed
- possible, because the operating system uses two screens: the physical
- screen (visible on your monitor) and the logical screen (usually, but not
- necessarily, the same as the physical screen). All graphical (GEM-)com-
- mands, including the TEXT-command, are always sent to the logical screen.
- But TOS will send PRINT-commands to the physical screen, unless you've
- opened a window! If the address of logical and physical screen is not the
- same, you have your invisible screen (except for PRINTing on the TOS-
- screen). The address of the logical screen must be a multiple of 256.
- Study the Procedures Initio.logical.screen, Swap.screen and
- Restore.physical.screen to see how you could use the described method for
- animation :
- PROCEDURE initio.logical.screen
- ' *** global : SCREEN.1% SCREEN.2%
- DIM screen.2|(32256)
- screen.2%=VARPTR(screen.2|(0))
- screen.2%=screen.2%+256-(screen.2% MOD 256)
- screen.1%=physbase%
- ~XBIOS(5,L:screen.2%,L:-1,-1) ! invisible screen.2 is now active
- RETURN
- '
- PROCEDURE swap.screen
- ' *** physical and logical screen are swapped
- SWAP screen.1%,screen.2%
- VSYNC ! avoid flash
- ~XBIOS(5,L:screen.2%,L:screen.1%,-1) ! swap the screens
- RETURN
- '
- PROCEDURE restore.physical.screen
- ~XBIOS(5,L:physbase%,L:physbase%,-1)
- RETURN
-
- On some ST-computers XBIOS 5 does not function properly after installation
- of a RAM-disk. In that case you could change the address of the logical
- screen with :
- VSYNC
- SLPOKE &H45E,adr%
-
-
- Font
-
- TOS has three built-in system-fonts. The default PRINT-font for High
- resolution is the 8x16 font (equals DEFTEXT ,,,13 for TEXT), while the 8x8
- font (equals DEFTEXT ,,,6) is used in Medium and Low resolution. You can
- switch between these two fonts with the following Procedures :
- PROCEDURE font.8x16
- LOCAL a$,adr%
- a$=MKI$(&HA000)+MKI$(&H2009)+MKI$(&H4E75)
- adr%=VARPTR(a$)
- adr%=C:adr%() ! address of font-table
- {INTIN}={adr%+8} ! pointer to 8x16 system-font
- VDISYS 5,2,0,102
- RETURN
- '
- PROCEDURE font.8x8
- LOCAL a$,adr%
- a$=MKI$(&HA000)+MKI$(&H2009)+MKI$(&H4E75)
- adr%=VARPTR(a$)
- adr%=C:adr%() ! address of font-table
- {INTIN}={adr%+4} ! pointer to 8x8 system-font
- VDISYS 5,2,0,102
- RETURN
- Both Procedures seem to have problems with the accessory QUICKST, but I
- never use it with GFA-Basic because there are other problems (INPUT) as
- well. If I don't use it, how did I discover this? Good question. The third
- font is used for icons, but for some reason can not become the current
- system-font. The VDI-function seems to work only with fonts containing
- characters of width 8 pixels. The function is not officially documented
- by Atari (?).
-
- You can replace the system-font by a font that has been created with
- FONTKIT by Jeremy Hughes (4114 byte A1_xxxxx.FON file for High
- resolution). Use the Procedure Change.font for this purpose and call the
- Procedure Normal.font to restore the original system-font :
- PROCEDURE change.font
- ' *** global : NEW.FONT! NORMAL.FONT%
- LOCAL adr%,new.font%
- '
- ' *** load A1_xxxxx.FON file (4114 bytes) here
- INLINE new.font%,4114
- '
- adr%=L~A-22
- normal.font%={adr%}
- SLPOKE adr%,new.font%
- new.font!=TRUE
- RETURN
- '
- PROCEDURE normal.font
- IF new.font!
- SLPOKE L~A-22,normal.font%
- new.font!=FALSE
- ENDIF
- RETURN
- I have not yet discovered how to use a FONTKIT-font with TEXT. Yes, I
- could load a new font after installing GDOS, but that's not what I'm
- looking for. Is there a quick and not-dirty way to convince GEM that a new
- font has been installed?
-
- A font-table for the 8x16 font occupies 4096 bytes (16 bytes/character,
- 256 characters). A FONTKIT-font usually has a name attached at the end,
- that's why I reserve 4114 bytes. TOS ignores the name completely, it's
- only used by the accessory FONSEL.ACC. You can load any 4096-byte font in
- the Procedure Change.font, you don't even have to change 4114 into 4096.
- Although you lose 18 bytes if you don't.
-
-
- 10. PRINTER
-
-
- Printer ready
-
- If you send data to your printer (HARDCOPY, LPRINT, etc.), your ST will
- wait 30 looooooong seconds if the printer happens to be not ready. Always
- check if the printer is ready before sending data to the printer, e.g. by
- calling the following Procedure :
- PROCEDURE printer.ready
- LOCAL k
- DO
- EXIT IF GEMDOS(17)
- ALERT 3," printer| | not ready !!",1," OK ",k
- LOOP
- RETURN
-
-
- HARDCOPY
-
- You can send a screendump to the printer by using the command HARDCOPY or
- by pressing <Alternate> <Help>. In both cases you can abort the screendump
- by pressing <Alternate> <Help>.
-
- You can use CONTROL.ACC to change the printer-parameters. Don't forget to
- save the desktop, in order to store these parameters in the file
- DESKTOP.INF. Look for '#b' with your disk-editor if you're curious. The
- parameters will only be read from DESKTOP.INF if CONTROL.ACC is installed
- after a reset! I suggest the use of XBIOS 33 (Setprt) in a program instead
- of using CONTROL.ACC. For a screendump from the High resolution screen to
- an Epson-compatible printer, clear bit 1 and set bit 2 :
- PROCEDURE screendump
- ~XBIOS(33,&X100) ! screendump to Epson(-compatible) printer
- HARDCOPY
- RETURN
- If you set bit 2, TOS assumes you connected an Epson-printer (960
- pixels/line). Clear bit 2 and TOS assumes you have an Atari-printer (1280
- pixels/line).
-
- If you use HARDCOPY, the width/height ratio of the printout does not
- correspond with that of the screen. For a reasonably fast 1:1 screendump,
- study the Procedure High.screendump.epson (Epson FX-80, or other 9-pin
- Epson-compatible printer) or the Procedure High.screendump.star24 (24-pin
- Star LC24-10) :
- PROCEDURE high.screendump.star24
- LOCAL m$,b$,k,scrn.start%,col,b%,x,d%,p|,b1|,b2|,b3|,n
- lf$=CHR$(10)
- ff$=CHR$(12)
- DEFFN bit.image$(m,d)=CHR$(27)+"*"+CHR$(m)+CHR$(MOD(d,256))+
- CHR$(d/256)
- DEFFN line.space$(n)=CHR$(27)+"3"+CHR$(n)
- initialize$=CHR$(27)+"@"
- scrn.start%=XBIOS(2)
- '
- LPRINT initialize$;
- FOR col=0 TO 79
- b%=scrn.start%+col
- LPRINT SPC(8);
- LPRINT @line.space$(24);
- LPRINT @bit.image$(33,800);
- FOR x=399 TO 0 STEP -1
- d%=ADD(b%,MUL(x,80))
- p|=BYTE{d%}
- IF p|=0
- OUT 0,0,0,0,0,0,0
- ELSE
- CLR b1|,b2|,b3|
- IF BTST(p|,0)
- b1|=7
- ENDIF
- IF BTST(p|,1)
- ADD b1|,56
- ENDIF
- IF BTST(p|,2)
- ADD b1|,192
- b2|=1
- ENDIF
- IF BTST(p|,3)
- ADD b2|,14
- ENDIF
- IF BTST(p|,4)
- ADD b2|,112
- ENDIF
- IF BTST(p|,5)
- ADD b2|,128
- b3|=3
- ENDIF
- IF BTST(p|,6)
- ADD b3|,28
- ENDIF
- IF BTST(p|,7)
- ADD b3|,224
- ENDIF
- OUT 0,b3|,b2|,b1|,b3|,b2|,b1|
- ENDIF
- NEXT x
- LPRINT
- EXIT IF INKEY$=esc$
- NEXT col
- LPRINT ff$;
- LPRINT initialize$;
- RETURN
-
- For a more flexible approach, study the Procedure Degas.screendump (Star
- LC24-10, possible formats : 27x17, 18x11, 13.5x8.5 or 9x5.5 cm).
-
- It should be possible to send only a (GET-)rectangle to your printer with
- XBIOS 36 (Prtblk) or V_OUTPUT_WINDOW (VDI 5,Escape 21). Anybody out there
- who knows how?
-
- Never, I repeat, never swap disks during a screendump, as this could be
- fatal for the new disk. TOS ignores the write-protect state during a
- screendump, so it will miss the disk-swap completely. TOS will use the old
- FAT for the new disk, and that usually is fatal (no pun intended).
-
- If you have installed a GFA-Basic printer-driver (e.g. PTEPSON.PRG), a
- screendump seems to be impossible. The bit-image mode of the printer can't
- be used after the driver has been installed.
-
-
- Printer-commands
-
- Most matrix-printers recognize either IBM- or Epson-commands (or both). I
- use the following Procedure to define the most important printer-commands
- for my Star LC24-10. Adapt the definitions to your own printer, but stick
- to the names for the global variables and functions. Other users could
- then use your programs easily after replacing the Procedure Initio.printer
- with their own :
- PROCEDURE initio.printer
- ' *** initializes global printer-variables for Star LC24-10
- ' *** DIP-switch settings :
- ' 1-1 OFF 2-1 ON
- ' 1-2 ON 2-2 ON
- ' 1-3 OFF 2-3 ON
- ' 1-4 ON 2-4 ON
- ' 1-5 ON 2-5 OFF
- ' 1-6 ON 2-6 OFF
- ' 1-7 ON 2-7 ON
- ' 1-8 ON 2-8 ON
- '
- LOCAL c$,f$
- c$=CHR$(27)
- f$=CHR$(28)
- '
- draft.char$=c$+"x0"
- lq.char$=c$+"x1"
- '
- courier.style$=c$+"k0"+lq.char$
- prestige.style$=c$+"k2"+lq.char$
- orator.style$=c$+"k3"+lq.char$
- script.style$=c$+"k4"+lq.char$
- '
- normal.char$=c$+"q0"
- outlined.char$=c$+"q1"
- shadow.char$=c$+"q2"
- outlined.shadow.char$=c$+"q3"
- '
- italic.on$=c$+"4"
- italic.off$=c$+"5"
- '
- emphasized.on$=c$+"E"
- emphasized.off$=c$+"F"
- '
- underline.on$=c$+"-1"
- underline.off$=c$+"-0"
- '
- bold.draft$=draft.char$+emphasized.on$+double.on$
- bold.lq$=lq$+double.on$
- bold.off$=emphasized.off$+double.off$
- '
- superscript.on$=c$+"S0"
- superscript.off$=c$+"T"
- subscript.on$=c$+"S1"
- subscript.off$=c$+"T"
- '
- epson.set$=c$+"t0"
- ibm.set$=c$+"t1"+c$+"6"
- DEFFN special.on$(n)=c$+"\"+CHR$(MOD(n,256))+CHR$(DIV(n,256))
- DEFFN ibm.special$(n)=c$+"^"+CHR$(n)
- DEFFN epson.special$(n)=ibm.set$+@ibm.special$(n)+epson.set$
- '
- pica$=c$+"P"
- '
- elite$=c$+"M"
- '
- condensed.on$=CHR$(15)
- condensed.off$=CHR$(18)
- '
- large.on$=c$+"W1"
- large.off$=c$+"W0"
- large.line$=CHR$(14)
- '
- courier.proportional$=courier.style$+c$+"p1"
- prestige.proportional$=prestige.style$+c$+"p1"
- proportional.off$=c$+"p0"
- '
- DEFFN master.mode$(n)=c$+"!"+CHR$(n)
- underline=128
- italic=64
- expanded=32
- LET double.strike=16
- emphasized=8
- condensed=4
- proportional=2
- elite=1
- '
- normal.size$=c$+"h"+CHR$(0)
- LET double.size$=c$+"h"+CHR$(1)
- quad.size$=c$+"h"+CHR$(2)
- LET double.height$=c$+"w1"
- normal.height$=c$+"w0"
- normal.width$=f$+"E"+CHR$(0)
- LET double.width$=f$+"E"+CHR$(1)
- triple.width$=f$+"E"+CHR$(2)
- '
- lf$=CHR$(10)
- DEFFN lf$(n)=c$+"f1"+CHR$(n)
- rev.lf$=c$+CHR$(10)
- '
- ff$=CHR$(12)
- rev.ff$=c$+CHR$(12)
- '
- justify.left$=c$+"a0"
- justify.right$=c$+"a2"
- justify.full$=c$+"a3"
- center$=c$+"a1"
- '
- reset$=c$+"@"
- '
- RETURN
- Of course you could delete all variables you don't need in your program.
- And it really would be nice if everyone uses the proposed names. One of
- the strong points of Public Domain GFA-programs is that it's easy to adapt
- a program. Or rather, it should be easy. Using the above Procedure is one
- step in the right direction.
-
-
- 11. FILES
-
-
- Floppy Write Test
-
- You are advised to switch the Write Verify test off :
- SPOKE &H444,0 ! test off
- SPOKE &H444,1 ! test on (default)
- According to experts like Dave Small and Bill Wilkinson the Verify test is
- a complete waste of valuable time if you write to a disk.
-
-
- Step Rate
-
- You will find the current step-rate of your drive with :
- PRINT DPEEK(&H440)
- The following values are possible :
- 0 - 6 ms
- 1 - 12 ms
- 2 - 2 ms
- 3 - 3 ms (default)
- The operating system only looks at this value after a reset (?). For an
- external 5.25"-drive you probably have to use 12 ms.
-
-
- RAM-disk
-
- Drive D is often reserved for a RAM-disk. GFA will recognize a RAM-disk
- with DFREE(4) only if it was already present at the time the interpreter
- was loaded.
-
- After switching off your 1040 ST you should wait at least 15 seconds
- before switching on again. Otherwise an old RAM-disk (or something else in
- RAM, e.g. a virus...) may still be present when you switch your computer
- on again.
-
- If a RAM-disk is not installed properly after a reset, the reason could be
- hidden in the drive bit-table at &H4C2. The old TOS does not clear this
- table and a RAM-disk can only be installed as drive D if bit 3 is cleared.
- By the way, use drive C (bit 2) only for a harddisk.
-
-
- DIR$()
-
- Use GEMDOS 25 (Dgetdrv) to find the current drive and combine this with
- DIR$(drive) to find the current path :
- drive=GEMDOS(25) ! drive 0 - 15
- drive$=CHR$(65+drive) ! drive A - P
- p$=DIR$(drive+1)
- IF p$=""
- path$=drive$+":\" ! main directory
- ELSE
- path$=drive$+":"+p$+"\"
- ENDIF
- With DIR$(0) you'll find the path of the current drive, not necessarily
- drive A. DIR$(1) returns the path of drive A. GEMDOS remembers the last
- used path for all available drives. See also the Standard Procedure
- Get.path.
-
- If you run GFA-Basic from the main directory and load a GFA-program from a
- folder, DIR$(0) will return the nullstring (""), not the folder. After
- using CHDIR with the folder-name, the correct path will be returned. I use
- CHDIR in the Shell-programs, so the Standard Global default.path$ will
- contain the path of the GFA-program. This makes life easier if you want to
- load data-files from the same folder, but don't know the precise path when
- you write the program. It would be nice if you could determine the path of
- the running GFA-program in the program itself.
-
- You can make an array-table of available drives with the aid of BIOS 10
- (Drvmap) :
- DIM drive!(15)
- SELECT DPEEK(&H4A6)
- CASE 1
- drive!(0)=TRUE
- CASE 2
- drive!(0)=TRUE
- drive!(1)=TRUE
- ENDSELECT
- table%=BIOS(10)
- FOR n=2 TO 15
- IF BTST(table%,n)
- drive!(n)=TRUE
- ENDIF
- NEXT n
-
- You can check if a harddisk is connected with :
- IF PEEK(&H472)<>0
- harddisk!=TRUE
- ENDIF
-
-
- DIR and FILES
-
- After DIR, FILES, TRON or DUMP you can slow down the scrolling with
- <CapsLock>. You can temporarily stop the scrolling by holding down the
- right <Shift>-key. The output after DIR fits on any screen, but the FILES-
- output is too wide for Low resolution. DIR will show only files in the
- current directory. FILES will also show folders (marked with *). With DIR
- (and FILESELECT) you will not be able to see "hidden" files or "system"
- files, but FILES will show all files. You can also search for hidden
- and/or system files with FSFIRST and FSNEXT by setting bit 1 and/or bit 2
- of the attribute-byte.
-
- Perhaps you have noticed that after the command FILES the first two lines
- are peculiar if you happen to be in a folder. The first "name" in a folder
- is always '.' (one dot) and the second always '..' (two dots). Time and
- date are incorrect, because the authors of (the old) TOS forgot to convert
- these to MS-DOS format. In case of nested folders, the operating system
- finds the preceding folder through a pointer of the '..'-file. That's why
- you can use 'CHDIR ..' to return to the preceding folder. Don't try this
- in the main directory, or you'll get an error.
-
-
- FSFIRST and FSNEXT
-
- The DTA-buffer is usually found at BASEPAGE+128 (it's always there after
- start-up), but you should not count on it. Use FGETDTA() to find the
- current address, before FSFIRST :
- dta.adr%=FGETDTA()
- e%=FSFIRST(format$,attr)
- FSFIRST returns -33 if no file has been found. FSNEXT returns -49 if no
- more files are found.
-
- In an accessory it's safer to create a new DTA-buffer :
- old.dta%=FGETDTA() ! old buffer
- dta$=STRING$(44,0)
- dta.adr%=V:dta$
- ~FSETDTA(dta.adr%) ! new buffer
- (...) ! FSFIRST/FSNEXT
- ~FSETDTA(old.dta%) ! restore old buffer
- The Desktop will appreciate all this extra work.
-
- The 44 byte DTA-buffer (Data Transfer Address) contains the following data
- after a succesful FSFIRST or FSNEXT :
- offset
- 0-20 - reserved
- 21 - attribute-byte
- 22-23 - time
- 24-25 - date
- 26-29 - file-length
- 30-43 - filename (including the extension, terminated by &H00)
- The attributes and the filename can be read from the buffer with :
- attr=BYTE{dta.adr%+21}
- file$=CHAR{dta.adr%+30}
-
- The DTA-buffer is not an exact copy of the relevant information in the
- directory of the disk. With a disk-editor you would find a slot of 32
- bytes for each file or folder :
- offset
- 0- 7 - file- or folder-name (without extension)
- 8-10 - extension
- 11 - attribute-byte
- 12-21 - reserved
- 22-23 - time
- 24-25 - date
- 26-27 - FAT-pointer
- 28-31 - file-length
- The first byte of the filename has a special meaning in the following
- cases :
- &H00 - free slot, never used before
- &HE5 - erased file, now free slot
- &H2E - subdirectory
- Both time and date are stored in MS-DOS format. Consult your GFA-manual
- for more information. The FAT-pointer, also in an MS-DOS format (Intel-
- format : first low byte, then high byte), points to the first cluster of
- the file. If you are looking at a folder, the FAT-pointer points to the
- cluster where you will find the directory of this folder (subdirectory).
- If you are looking at a subdirectory (i.e. you are in a folder), the first
- two slots are reserved for the files '.' and '..' (&H2E and &H2E2E). This
- has already been mentioned in the paragraph 'DIR and FILES'. Finally, the
- file-length is stored in, you guessed it, MS-DOS format. You might wonder
- what MS-DOS has to do with Atari-disks. Read the paragraphs 'Disk Format'
- and 'File Allocation Table' for the explanation.
-
- If you use the attribute-byte &X10000 you will find both folders and
- files! If the folders in a directory don't have an extension and all files
- do have an extension, you could find all folders in the main directory as
- follows :
- e%=FSFIRST("\*",&X10000) ! and e%=FSNEXT() for next folders
-
- If you can't use this simple method, you'll have to check after each
- successful FSFIRST/FSNEXT if it's a folder or a file :
- IF BTST(BYTE{dta.adr%+21},4)
- (...) ! yes, it's a folder
- ENDIF
-
- Use the attribute-byte 0 (i.e. no bits set) to find ordinary files only.
-
- Use attribute-byte &X1000 to find the disk-name :
- dta.adr%=FGETDTA()
- e%=FSFIRST("\*.*",&X1000) ! finds disk-name only, not files
- disk.name$=CHAR{dta.adr%+30}
-
- You can read the attributes of a file or folder with GEMDOS 67 (Fattrib) :
- attr%=GEMDOS(67,L:V:filename$,0,0)
- If the file (or folder) is not found, attr% is -33 (or -34), otherwise
- attr% contains the attributes in the usual format. You can even change the
- attributes of files with :
- r%=GEMDOS(67,L:V:filename$,1,attribute%)
- It's not possible to change the attributes of folders or the disk-name
- with GEMDOS 67. One way to do that is to change the directory-sector with
- the aid of BIOS 4 (Rwabs). If you really feel the urge to experiment, you
- should realize that one tiny mistake could ruin the disk.
-
-
- EXIST
-
- You can use EXIST to test if a folder exists, but only if the folder
- contains at least one file :
- IF EXIST("\FOLDER\*.*")
- (...) ! folder found
- ELSE
- (...) ! folder not found or empty folder
- ENDIF
-
-
- LOF
-
- The length of a file is easily determined with LOF :
- OPEN "I",#1,file$
- length%=LOF(#1)
- CLOSE #1
-
- To determine the number of records in a random file you could divide the
- file-length by the total FIELD-length.
-
-
- TOUCH
-
- Use this method with TOUCH :
- OPEN "U",#1,file$
- TOUCH #1
- CLOSE #1
-
-
- NAME
-
- With the old TOS you can only change the name of files, not of folders.
- Even from the desktop you can't change the name of a folder, so choose it
- carefully.
-
-
- KILL
-
- KILLing a file does not erase it from the disk. The first byte of the
- filename is changed to &HE5. Unfortunately you can't restore a killed file
- by simply changing this byte with a disk-editor. The operating system will
- be able to find the first cluster of the restored file, because the first
- FAT-pointer is located in the directory. The next clusters can only be
- found through the FAT (File Allocation Table), but after KILL all pointers
- to this file are irreversibly erased. If you have not killed any file on
- the disk before your fatal mistake, you are extremely lucky and will find
- all clusters have been stored consecutively. But after some killing and
- saving on the disk, the file could be dispersed over the entire disk. Some
- programs are able to help you, but you will have to recognize clusters as
- belonging to the killed file. That's easy with ASCII-files, but almost
- impossible with other files. So, don't KILL unless you have to.
-
-
- File Copy
-
- You can copy a file source$ to dest$ (use complete pathnames!) with :
- PROCEDURE file.copy(source$,dest$)
- LOCAL block%
- OPEN "I",#90,source$
- OPEN "O",#91,dest$
- block%=LOF(#90)
- WHILE block%>32000
- PRINT #91,INPUT$(32000,#90);
- SUB block%,32000
- WEND
- PRINT #91,INPUT$(block%,#90);
- CLOSE #90
- CLOSE #91
- RETURN
-
- Do not copy a file "to itself" on a harddisk. Thanks to yet another bug in
- TOS, this action could completely wipe out the harddisk. Or perhaps this
- should be called a feature of TOS, put there to punish the crazy user who
- tries to copy a file to itself.
-
-
- Disk Format
-
- A disk contains 80 concentric tracks (numbered 0 - 79) or more. Sometimes
- the expression "cylinder" is used instead of "track". Each track is
- divided into 9, 10 or even 11 sectors. One sector can contain 512 data-
- bytes. In order to be compatible with MS-DOS, TOS formats a disk with 80
- tracks and 9 sectors/track. Actually it's easy to fit 10 sectors in one
- track. With a little more effort you can create room for 11 sectors, but
- some drives run slightly too fast and are not able to read the 11th
- sector!
-
- With a disk-editor you can examine the 512 data-bytes of a sector, but
- you can't examine the sector-layout without accessing the Floppy Disk
- Controller (FDC) directly. In that case you would find the following
- layout for each sector :
- data-separator (GAP) - 15 bytes
- ID-Address mark - 1 byte
- sector-header - 4 bytes (track, side, sector, size)
- CRC of sector header - 2 bytes
- data separator - 37 bytes
- Data-Address Mark - 1 byte
- data bytes - 512 bytes
- CRC of data bytes - 2 bytes
- data separator - 40 bytes
- The data separator bytes are there to synchronize the FDC properly. The
- FDC recognizes the sector-header by the preceding ID-Address mark. The
- sector-header itself contains information about the current track, side
- and sector and also about the size of the data-field (usually 512 bytes).
- The FDC checks both the sector-header and the data-field for corrupted
- bytes by comparing a computed "checksum" with the stored CRC-value. The
- operating system cannot read/write one byte from/to a sector, only
- complete sectors are read or written. GFA-Basic takes care of all the
- dirty work.
-
- First some bad news. A CRC-error is not always recognized by the ROM of
- 520 ST's and 1040 ST's (bug in XBIOS 8, Floprd). If your palms are now
- getting sweatty, you could check your most precious disks with XBIOS 19
- (Flopver). This function checks for 'lost data, RNF- or CRC-errors'.
- Create a buffer of 1024 bytes and call XBIOS 19. A sector (512 bytes) is
- loaded from the disk in drive A or B (0 or 1) into the second part of the
- buffer and checked. If a bad sector is found, the sector-number is stored
- as a word in the first part of the buffer. After checking all sectors in
- one track you have to examine the word-list in the buffer. Hope you will
- find only &H0000 there. I leave the writing of this program as an exercise
- to the reader. Never thought I would use that phrase myself. Allright,
- here's something to get started :
- buffer$=STRING$(1024,0)
- adr%=V:buffer$
- r%=XBIOS(19,L:adr%,L:0,drive,1,track,side,9) ! if 9 sectors/track
- You should now be able to find out if the track on this side (0 or 1) is
- OK. Good luck.
-
- You can use BIOS 7 (Getbpb) to examine the disk-format in the so-called
- BIOS-Parameter-Block (BPB) of the disk :
- bpb.adr%=BIOS(7,drive) ! address of BPB, or 0 (= error)
- In 9 words you'll find the following information in the BPB :
- offset
- 0 - bytes/sector (usually 512)
- 2 - sectors/cluster (usually 2)
- 4 - bytes/cluster
- 6 - number of directory-sectors
- 8 - length of FAT
- 10 - first sector of second FAT
- 12 - first data-sector
- 14 - total clusters
- 16 - flag (not used)
-
- Use GEMDOS 54 (Dfree) to find out how many free clusters are available, or
- simply use DFREE if you want to know how many free bytes are available on
- a drive. Due to a bug, GEMDOS misses the last two clusters on a disk. You
- can't write to these clusters (2048 bytes down the drain...), but you can
- read these clusters if they do contain data. That would be a miracle, or
- an MS-DOS disk.
-
- You'll probably use XBIOS 10 (Flopfmt) to format a disk from GFA-Basic. If
- you do, use &H0000 as the virgin-value for the first 18 sectors, and then
- &HE5E5 for all data-sectors. You can use either 9 or 10 sectors/track, not
- 11. If you use 10 sectors/track, you should fill the first two tracks with
- &H0000 and fill sectors 19 and 20 with &HE5E5 afterwards (read the
- paragraph 'Sectors'). I don't recommend more than 80 tracks, certainly not
- more than 82 tracks. If XBIOS 10 returns a value other than 0, you'll find
- a list of bad sectors in the buffer you used (terminated with &H00). If
- one of the first 18 sectors is bad, you can throw the disk away.
-
- Using XBIOS 10, the interleave-factor should be 1. This means the sectors
- on a track are numbered consecutively: 1,2,3,4,etc. I don't understand
- why some programmers use another value and call it 'Fast Format'. The FDC
- needs more time to read a complete track if the interleave-factor is not
- 1. Perhaps they try to create the so-called Twisted (or Skewed) format.
- TOS loses time if the head moves to the next track. Because the Seek with
- Verify flag is set, the FDC first verifies the track-number and then reads
- the sector-number. While checking the track-number, sector 1 was passing,
- so we have to wait for one complete spin of the disk (200 ms, yawn) until
- sector 1 can be read. One solution is to clear the Seek with Verify flag,
- but that could lead to nasty problems if the head still rattles slightly
- at the time sector 1 is read. The best solution is the Twisted format
- (adopted by Atari from the Mega ST onwards). For a single-sided disk with
- 9 sectors on one track this means :
- track 0 : sector 1,2,3,4,5,6,7,8,9
- track 1 : sector 8,9,1,2,3,4,5,6,7
- track 2 : sector 6,7,8,9,1,2,3,4,5
- etc.
- Now, sector 1 is encountered almost immediately after the track-number is
- verified. A 1-sector offset is not possible, but a 2-sector offset is
- enough to settle the rattling head. It is impossible to read data faster
- from a disk! But I'm afraid you can't format a Twisted disk with XBIOS 10
- if you have an old TOS. You have to use a special format-program.
-
- If you format a disk from the desktop, bad clusters are flagged with a
- special value in the FAT. However, if TOS 1.4 encounters a bad sector,
- something goes wrong and the FAT is corrupted. One more reason to quit
- smoking, because smoke-particles definitely constitute a serious hazard to
- the health of your disks.
-
- You can use XBIOS 18 (Protobt) to create a bootsector on the formatted
- disk. Don't worry about the media-byte (disk-type), because TOS doesn't
- use it. Do use &H1000000 to generate a random serial number, because it is
- very important that different disks have different serial numbers! Write
- the bootsector to the disk with XBIOS 9 (Flopwr), not with BIOS 4 (Rwabs):
- r%=XBIOS(9,L:buffer%,L:0,drive%,1,0,0,1)
-
- Why are different serial numbers so important? If TOS suspects a disk-
- swap, the serial number is read from the disk. A disk-swap can only be
- recognized if the number on the new disk is different from the old number.
- If the new disk contains the same serial number, TOS uses the FAT of the
- previous disk. Writing to a swapped disk will probably zap it, if you
- follow me. Disk-copiers copy everything, including serial numbers. Be
- careful!
-
- Although it is possible to format a disk from GFA-Basic, I don't recommend
- it (now he tells us...). My favourite format is :
- 80 tracks
- 10 sectors/track
- Twisted format
- I use TWISTER.PRG (not Public Domain, as far as I know), but you could use
- a Public Domain program like DCOPY (actually Shareware). The Desktop can't
- copy a Twisted disk, but file-copy is always possible. DCOPY copies any
- format, including Twisted format.
- File Allocation Table (FAT)
-
- The first sector on a disk is the boot-sector. The next five sectors are
- reserved for the FAT. And the next five for a copy of the FAT (actually
- it's the other way around). Finally, the main (or root) directory occupies
- the next 7 sectors (32 bytes for each slot). This means that the first 18
- sectors (No. 0-17) are reserved for the operating system. All other
- sectors are available for storing files.
-
- The storage-unit for files is a cluster. A cluster consists of two
- consecutive sectors (1024 bytes). A file that contains only 1 byte will
- therefore still occupy 1024 bytes (1 K) on the disk. When a file is saved,
- the operating system looks for the first empty cluster, then the next,
- etc. Information about available clusters is stored in the FAT as a
- collection of pointers. Due to inefficient programming, the search for
- free clusters takes a long time. Try DFREE on a harddisk and you'll agree.
- Install a program like FATSPEED.PRG (Public Domain, by Ulrich Kuebler) to
- speed this up!
-
- The first three bytes of the FAT are not used by TOS, but are there to
- enable MS-DOS to read an ST-formatted disk. TOS writes &HF7FFFF, where the
- first byte (&HF7) is supposed to be the media-byte. Unfortunately MS-DOS
- doesn't understand this and refuses to read the directory properly. I'm
- not quite sure why, but changing the first three bytes to &H000000 seems
- to work. You could try &HF8FFFF (80 tracks, 9 sectors/track, single sided
- disk) or &HF9FFFF (double sided disk) instead. Or you could use the media-
- byte at offset 21 from the bootsector. To make your MS-DOS friends
- completely happy, you should change the first three bytes of the bootsec-
- tor to: &HEB3890. Sometimes (DOS 4.0 ?) you have to change the next three
- bytes as well: &H49424D (that's IBM in ASCII; please watch your language).
- Better still, let them use their own disk editor on their MS-DOS computer
- (e.g. Norton Utilities). Why should you do all the work? By the way, your
- ST should be able to use an MS-DOS disk without any modifications.
-
- Each FAT-pointer consists of one and a halve byte (3 nibbles, i.e. 12
- bits). In hexadecimal notation this means three digits for one pointer.
- The first pointer (No. 0) points to cluster No. 0, the second to No. 1,
- etc. . Because the first two pointers don't count, you have to subtract
- two to find the actual cluster (pointer 2 points to cluster No. 0, etc.).
- The first cluster starts at sector No. 18 (remember, sectors 0-17 are
- reserved for bookkeeping), so you could find the first sector of a cluster
- with :
- (pointer - 2) * 2 + 18
- The second sector of this cluster is of course the next one.
-
- TOS reads the pointers in a peculiar (MS-DOS) way. Suppose the FAT-sector
- starts with :
- F7 FF FF 03 40 00 FF 0F 00
- Without further explanation, this translates to :
- FAT-pointer 0 and 1 are ignored
- FAT-pointer 2 = &H003 (next cluster on sector 20 + 21)
- FAT-pointer 3 = &H004 (next cluster on sector 22 + 23)
- FAT-pointer 4 = &HFFF (last cluster of this file)
- FAT-pointer 5 = &H000 (free cluster)
- In order to understand this, you have to consult the following table :
- &H000 : cluster still available
- &HFF1 - &HFF7 : bad cluster, never available
- &HFF8 - &HFFF : last cluster of this file (End Of File)
- &H002 - &HFF0 : pointer to next cluster
- Assuming the FAT-pointer &H002 at offset 26 in the directory (you'll find
- &H0200 with a disk editor, that's Intel format with low byte first again),
- you should be able to figure out that this file will be found in sectors
- 18 through 23. Sectors 24/25 are empty, so this cluster is available for a
- new file. Any questions? The one big advantage of all this is compatibi-
- lity with MS-DOS disks. With TOS 1.4 your ST-disks can be made completely
- compatible, so you don't even have to change a few bytes.
-
- Right, you have just read the Fatman-book. The movie will be released
- shortly, but you can NOW buy those fabulous Fatman-shirts and fantastic
- Fatman-buttons. Call Atari for further details.
-
-
- Sectors
-
- There are two different methods to assign a number to a sector. The first
- one is to number the "physical" sectors in each track from 1 to 9
- (assuming 9 sectors/track). This way you could say the bootsector is
- sector 1 on track 0 (on side 0 if the disk is double sided). But GEMDOS
- doesn't care about tracks or sides, it counts "logical" sectors from 0 to
- 719 (80 tracks, 9 sectors/track, one sided disk) or from 0 to 1439 (double
- sided disk). According to GEMDOS, the bootsector is on sector 0. And on a
- double sided disk, physical sector 1 on track 0 of side 1 (the other side)
- would be sector 9.
-
- With BIOS 4 (Rwabs) you can read (and write) complete logical sectors :
- buffer$=SPACE$(512) ! 512 bytes for 1 sector
- buffer%=V:buffer$ ! address of buffer
- r%=BIOS(4,0,L:buffer%,1,sector%,drive%) ! load the sucker
- You would load the bootsector from the disk in drive A with :
- r%=BIOS(4,0,L:buffer%,1,0,0)
- You can use BIOS 4 not only with floppy disks, but also with a harddisk
- or a RAM-disk. After loading a sector, you can read one byte with :
- b|=BYTE{buffer%+n} ! n from 0 to 511
- You can read a word with :
- w=WORD{buffer%+n}
- But only if the word starts at an even address. Otherwise you have to use:
- w=BYTE{buffer%+n+1}+256*BYTE{buffer%+n}
- If necessary, you can speed this up by using the special integer commands
- for addition and multiplication. How about this Polish monster :
- DEFFN word(adr%)=ADD(BYTE{SUCC(adr%)},MUL(256,BYTE{adr%}))
- Then you would use :
- w=@word(ADD(buffer%,n))
-
- If you use BIOS 4 to write a sector after formatting a disk, you should
- use '3' as a flag (not '1') :
- r%=BIOS(4,3,L:buffer%,1,sector%,drive%)
-
- You can also read and write physical sectors with XBIOS 8 (Floprd) and
- XBIOS 9 (Flopwr). With these commands you could even read/write all
- sectors on one track. This is the only way to read a track, because
- reading a complete track is impossible due to a bug in the FDC.
-
- If you swap a disk after loading/writing a sector you should be careful.
- Testing with BIOS 9 (Mediach) you could miss the disk-swap. This could be
- fatal, because TOS uses the FAT of the other disk! I think you could use
- BIOS 7 (Getbpb) in most cases, but use the Procedure Force.mediach if in
- doubt :
- PROCEDURE force.mediach
- LOCAL x$,old.vector%,a%
- x$=SPACE$(12)
- old.vector%=LPEEK(&H47E)
- a%=V:x$
- DPOKE a%,&H2B7C
- LPOKE a%+2,old.vector%
- DPOKE a%+6,&H47E
- DPOKE a%+8,&H7002
- DPOKE a%+10,&H4E75
- SLPOKE &H47E,a%
- ~DFREE(0) ! current drive
- RETURN
- To be more precise, BIOS 7 can't be used in the following situation :
- - TOS reads a sector
- - you swap disks
- - you use BIOS 7 in your program
- - TOS reads a sector
- Now TOS will assume there has been no disk-swap, because there has been no
- disk-swap after the last BIOS 7 call! You definitely need the Procedure
- Force.mediach in this case.
-
- By the track, TOS also ignores disk-swaps during a screendump (HARDCOPY),
- or while using DMA (harddisk, laser printer). TOS detects a disk-swap by
- monitoring the write-protect state. To see this, you should turn all
- lights off and then watch the drive-light closely. Closer. You can turn
- the lights on again. If the drive is empty, TOS gets a write-protect
- signal and assumes the user might have swapped disks. BIOS 9 should return
- '1' at this point. TOS checks if you really did swap disks by reading the
- serial number from the bootsector and comparing it with the current
- number. Only if these numbers are different, a disk-swap is recognized by
- TOS (BIOS 9 should return '2' now). You probably deduced that TOS will
- read the bootsector also if you use a write-protected disk. Continuously
- reading the bootsector is a waste of time, so TOS waits 1.5 seconds before
- looking again. Never swap disks within 1.5 seconds after a read/write-
- operation. The drive keeps spinning for 2 seconds, so you can't go wrong
- if you wait until the drive-light is off before swapping disks.
-
- Bootsector
-
- In the following table you'll find the lay-out of a bootsector. All words
- are in Intel-format, except CHKSUM.
-
- offset length name
-
- 0 2 &H6038 = branch to bootroutine
- 2 6 FILLER fill-bytes
- 8 3 SERIAL serial-number of disk
-
- 11 2 BPS bytes/sector (512)
- 13 1 SPC sectors/cluster (2)
- 14 2 RES reserved sectors (1, Bootsector)
- 16 1 NFATS number of FAT's (2)
- 17 2 NDIRS max. entries in main directory
- 19 2 NSECTS total sectors
- 21 1 MEDIA media-byte (not used by TOS)
- 22 2 SPF sectors/FAT (5)
- 24 2 SPT sectors/track
- 26 2 NSIDES sides (1 or 2; no joke this time)
- 28 2 NHID hidden sectors (ignored by TOS)
-
- 30 2 EXECFLAG start of bootcode : flag
- 32 2 LDMODE 0=load FNAME; <>0=load sectors
- 34 2 SSECT first sector (LDMODE<>0)
- 36 2 SECTCNT number of sectors
- 38 4 LDADDR load at this RAM-address
- 42 4 FATBUF address of FAT-buffer
- 46 11 FNAME filename (nnnnnnnneee) (LDMODE=0)
- 57 1 DUMMY fill-byte
-
- 58 boot-routine (could be a boot-virus)
-
- 510 2 CHKSUM
-
- TOS determines if the bootsector is executable by adding all bytes. If
- this sum (AND &HFFFF) equals &H1234, the bootsector is executable. If you
- use GFA-Basic this probably means you have an ancient ST with TOS in RAM,
- or a boot-virus. A normal GFA-disk has only &H00- or &HE5-bytes from the
- offset 58.
-
-
- BLOAD
-
- BLOAD needs an address, unless you have used BSAVE in the same program
- before. In that case the BSAVE-address is used automatically by BLOAD if
- you don't specify a new address.
-
- BLOAD (BSAVE) is easier to use than BGET (BPUT), because you don't have to
- open the file. But with BLOAD you can only load the entire file, while
- BGET allows you to load any part of the file.
-
-
- INP and OUT
-
- Both INP and OUT can also be used with 2-byte and 4-byte integers :
- a|=INP(#n)
- a&=INP&(#n)
- a%=INP%(#n)
- OUT #n,a|
- OUT& #n,a&
- OUT% #n,a%
-
-
- INPUT and LINE INPUT
-
- Because GFA now uses a 4K-buffer for each opened file (version 3.07),
- reading data from a file with (LINE) INPUT goes much faster.
-
-
- STORE and RECALL
-
- For very fast loading and saving of string-arrays, you should use RECALL
- and STORE. You can also store (or recall) a part of an array as follows :
- STORE #1,txt$(),10 ! store elements 0 through 9
- STORE #1,txt$(),5 TO 10 ! store elements 5 through 10
-
- The correct syntax is :
- STORE #i,x$()[,n[ TO m]]
- RECALL #i,x$(),n[ TO m],x% (use n=-1 for complete array)
- Of course you have to open the file first.
-
- If you STORE a text-array, GFA puts &H0D0A (CHR$(13);CHR$(10)) after each
- element. This is the same format as used by 1st Word Plus (WP Mode off,
- i.e. ASCII-mode), Tempus, etc.
-
- If you're going to show more than a few text-lines, you could enter the
- text as DATA-lines, e.g. with the Procedures Initio.text.array and
- Initio.text.array.low (for Low resolution) :
- PROCEDURE initio.text.array
- ' *** global : TEXT$()
- LOCAL lines,line$,n
- lines=0
- RESTORE txt.data
- READ line$
- REPEAT
- INC lines
- READ line$
- UNTIL line$="***"
- ERASE text$()
- DIM text$(lines)
- RESTORE txt.data
- FOR n=1 TO lines
- READ text$
- text$(n)=SPACE$(5)+text$ ! left margin of 5 spaces !!
- NEXT n
- txt.data:
- DATA text
- DATA ***
- RETURN
-
- If you are going to show more text, I suggest you use 1st Word Plus, or
- any other wordprocessor or text-editor that can save your text as an
- ASCII-file. With 1st Word Plus, I use a Ruler length of 70 and the
- following Page Layout Form :
- Paper length 66
- TOF margin 19
- Head margin 4
- Foot margin 4
- BOF margin 19
- Lines/page 20
- Enter the text and save as an ASCII-file (turn WP Mode off before saving).
- In your GFA-Basic program you would first load the text in a string-array:
- DIM text$(lines)
- OPEN "I",#1,file$
- RECALL #1,text$(),-1,lines% ! lines% ≤ lines+1
- CLOSE #1
- Then you could use the Procedure Show.text.page (High or Medium resolu-
- tion) to show the text with 20 lines/screen. The Procedure uses a left and
- right margin of 5 characters, so that's why you have to use 70 charac-
- ters/line in your wordprocessor. If the text-array is full, you won't get
- an error if the file contains more text-lines!
-
- You could use a 2-dimensional string-array to store first and last names :
- name$(i,0)=first_name$
- name$(i,1)=last_name$
- Again, STORE and RECALL are very fast. But it is now necessary to use
- exactly the same dimensions with RECALL that you used with STORE. If the
- dimensions don't match, the array will be scrambled after RECALL.
-
-
- FILESELECT
-
- Don't use the underscore '_' in the path-line of the Fileselector, because
- a bug in the old TOS will then cause a few bombs. Owners of a Mega ST or
- TOS-version 1.4 can use as many underscores as they like.
-
- Changing drives in the Fileselector (old TOS) is not easy. Click on the
- path-line and press <Esc> to clear the line. Enter the drive, e.g. 'D:\',
- and click on the bar under the path-line in order to read the new
- directory. Also click on this bar after changing disks (in this case you
- would press <Esc> on the desktop). Selecting drive A is easier: just clear
- the path-line and click on the bar. The TOS-code that takes care of all
- this work is also known as the bartender.
-
- If you have changed the extension in the path-line, you should click just
- below the bar. If you click on the bar, the path-line is overwritten with
- '*.*' ! That same bartender strikes again.
-
- The correct syntax for calling the Fileselector is :
- FILESELECT [#title$,]path$,default$,file$
- The title is only used in TOS-version 1.4 and ignored in older TOS-
- versions. The default$ usually is the null-string (""), but don't use the
- null-string for path$ or the Fileselector will freeze. Use "\*.*" as path$
- for all files in the main directory. Do use the backslash in the pathname
- (e.g. "A:\*.*"). Due to a bug in GEM, the wrong drive is sometimes used if
- you forget the backslash ("A:*.*"). If the user has selected a file, file$
- will contain the path and filename. The file$ will be the null-string if
- the user selected <Cancel>. A third possibility is easily overlooked: the
- user could have selected <OK> without choosing a file. In that case file$
- contains the current path, ending with a backslash.
-
- Do not despair if you need a title, but don't have TOS 1.4. Try the
- Procedure Fileselect (High or Medium resolution) or Fileselect.low :
- PROCEDURE fileselect(path$,default$,txt$,left$,right$,VAR file$)
- ' *** print optional title (light text) to left and right
- LOCAL screen$,y.fac
- SGET screen$
- CLS
- IF high.res!
- y.fac=1
- ELSE
- y.fac=2
- ENDIF
- DEFTEXT black,2,900,32
- TEXT 100,350/y.fac,300/y.fac,left$
- DEFTEXT ,,2700
- TEXT 540,50/y.fac,300/y.fac,right$
- DEFTEXT ,0,0,13
- PRINT AT(1,3);@center$(txt$)
- GRAPHMODE 3
- DEFFILL black,1
- BOUNDARY 0
- IF high.res!
- BOX 157,25,482,54
- PLOT 157,25
- PBOX 159,27,480,52
- ELSE
- BOX 157,12,482,27
- PLOT 157,12
- PBOX 160,14,479,24
- ENDIF
- BOUNDARY 1
- GRAPHMODE 1
- FILESELECT path$,default$,file$
- SPUT screen$
- RETURN
- As a programmer, you should take into account the possibility that a user
- might start your program from drive A, a harddisk or a RAM-disk. I use the
- Standard Global default.path$ to remember where the program was started.
- If the user changes the (default) path in the Fileselector, you should
- note the change and use the new path if the Fileselector is called again.
- Use the Procedure Parse.filename for this purpose :
- PROCEDURE parse.filename(parse.name$,VAR drive$,path$,file$,ext$)
- LOCAL pos,first,last,last!,search,parse.file$
- '
- parse.name$=UPPER$(parse.name$)
- IF MID$(parse.name$,2,1)=":"
- drive$=LEFT$(parse.name$,1)
- ELSE
- drive$=CHR$(65+GEMDOS(&H19)) ! current drive
- ENDIF
- '
- pos=1
- last!=FALSE
- last=0
- first=INSTR(1,parse.name$,"\")
- REPEAT
- search=INSTR(pos,parse.name$,"\")
- IF search>0
- pos=search+1
- last=search
- ELSE
- last!=TRUE
- ENDIF
- UNTIL last!
- IF last>0 ! backslash discovered
- path$=MID$(parse.name$,first,last-first+1)
- parse.file$=MID$(parse.name$,last+1)
- ELSE ! no '\'
- path$=""
- pos=INSTR(1,parse.name$,":")
- IF pos>0
- parse.file$=MID$(parse.name$,pos+1)
- ELSE
- parse.file$=parse.name$
- ENDIF
- ENDIF
- pos=INSTR(parse.file$,".")
- IF pos>0 ! name with extension
- ext$=MID$(parse.file$,pos+1)
- file$=LEFT$(parse.file$,pos-1)
- ELSE ! name without extension
- ext$=""
- file$=parse.file$
- ENDIF
- RETURN
-
- If you have a joystick with Auto-Fire on, you should switch it off. The
- Fileselector doesn't like Auto-Fire. Neither do I.
-
- The Fileselector will warn you with a modest 'ping' if it counts more than
- 100 files/folders. It will show only the first 100 files/folders. I think
- 45 files in one folder is really the limit for impatient users like
- myself. More than 100 is a crime that should be punished with more than a
- 'ping'. The main directory of drive A can't contain more than 112
- files/folders, because the 7 directory-sectors contain 112 32-byte slots.
-
- Every time you open a folder (in the Fileselector, or otherwise), TOS
- stores information about the folder in a table. After opening/accessing 40
- folders, TOS will delete clusters, cross-link clusters, and do other nasty
- things. Your disk could be completely destroyed, thanks to this bug. Atari
- enlarged the buffer in TOS 1.2 and fixed the bug in TOS 1.4. Atari also
- distributes the program FOLDRxxx.PRG to extend the 40-folder limit with
- 100 (FOLDR100.PRG) or more. Be careful with SHOW INFO, it's easy to exceed
- the 40-folder limit! You could recognize a disaster by one of the
- following symptoms :
- - unexpected '0 bytes in 0 items' message in directory
- - folder-names trashed (usually lots of Greek letters)
- - Show Info crashes or shows weird information
- Don't be afraid of a new virus. It's only a TOS-bug. Immediately reset
- your ST, try to salvage as many files as possible and reformat the disk.
- If all files are lost, you will have to use your back-up files. If you
- don't have back-up files, you have nothing left but my sympathy.
-
-
- 12. MIDI
-
-
- INPMID$
-
- With the command INPMID$ the internal Midi-buffer is read and at the same
- time cleared. You can find the buffer with XBIOS 14 (Iorec) :
- adr%=LPEEK(XBIOS(14,2))
- The default size of this buffer is only 128 bytes, but you can use the
- Procedure Change.midi.buffer to change the size of the buffer :
- PROCEDURE change.midi.buffer(size%)
- LOCAL ptr%
- ptr%=XBIOS(14,2)
- ERASE buffer|()
- DIM buffer|(size%-1)
- LPOKE ptr%,VARPTR(buffer|(0)) ! start-address of new buffer
- DPOKE ptr%+4,size% ! size
- DPOKE ptr%+6,0 ! buffer-head
- DPOKE ptr%+8,0 ! buffer-tail
- DPOKE ptr%+10,0 ! low mark (not used)
- DPOKE ptr%+12,size%-1 ! high mark (not used)
- RETURN
- Because handshake is impossible with Midi, you need a large buffer if
- Midi-bytes are coming in fast.
-
-
- INP
-
- If you use INP(3) to read Midi-bytes, you should first check with INP?(3)
- if the Midi-buffer contains data. If you use INP(3) and no bytes are
- available, your ST will freeze. Until you reset the computer.
-
-
- Midi-commands
-
- Study the Procedures in the file MIDI.LST to see how you can use Midi-
- commands in GFA-Basic. With the Procedures Record.midi and Play.midi you
- could write a simple Midi-recorder. And the Procedure Midi.monitor can be
- used to examine incoming Midi-messages.
- PROCEDURE record.midi(VAR midi.byte|(),midi.time%())
- ' *** uses Procedure All.midi.off
- ' *** global : LAST.MIDI.BYTE%
- LOCAL last%,buffer$,i%,t%,time%,byte|,delay%,j%,m$,k
- ARRAYFILL midi.byte|(),0
- ARRAYFILL midi.time%(),0
- last%=DIM?(midi.byte|())-1
- m$=STR$(last%)+" bytes available ;| |stop recording|"
- m$=m$+"by pressing space"
- ALERT 3,m$,1,"RECORD",k
- REPEAT
- UNTIL INKEY$=""
- buffer$=INPMID$ ! clear MIDI-buffer
- i%=1
- t%=TIMER
- REPEAT
- IF INP?(3)
- byte|=INP(3)
- IF byte|<>254
- time%=SUB(TIMER,t%)
- midi.byte|(i%)=byte|
- midi.time%(i%)=time%
- INC i%
- ENDIF
- ENDIF
- UNTIL i%=last% OR INKEY$=" "
- last.midi.byte%=i%-1
- @all.midi.off
- delay%=midi.time%(1) ! subtract time for first note
- FOR j%=1 TO i%
- SUB midi.time%(j%),delay%
- NEXT j%
- m$="|"+STR$(i%)+" bytes recorded"
- ALERT 3,m$,1," OK ",k
- RETURN
- '
- PROCEDURE play.midi(VAR midi.byte|(),midi.time%())
- ' *** uses Procedure All.midi.off
- LOCAL m$,k,i%,t%,time%
- m$="record of "+STR$(INT(midi.time%(last.midi.byte%)/200))+
- m$=m$+" seconds| |(stop by pressing space)"
- ALERT 3,m$,1,"PLAY",k
- REPEAT
- UNTIL INKEY$=""
- i%=1
- t%=TIMER
- REPEAT
- time%=SUB(TIMER,t%)
- IF midi.time%(i%)<=time%
- OUT 3,midi.byte|(i%)
- INC i%
- ENDIF
- UNTIL i%=last.midi.byte% OR INKEY$=" "
- @all.midi.off
- RETURN
- '
- PROCEDURE midi.monitor
- LOCAL m$,k,byte|,byte$,hex$,bin$,buffer$,key$
- byte$=SPACE$(3)
- hex$=SPACE$(2)
- bin$=SPACE$(8)
- m$="all incoming bytes|(except 254) are|printed on screen ;|"
- m$=m$+"stop by pressing space"
- ALERT 1,m$,1,"START",k
- m$="press|<Return>|for CLS"
- ALERT 1,m$,1," OK ",k
- REPEAT
- UNTIL INKEY$=""
- buffer$=INPMID$ ! clear MIDI-buffer
- CLS
- PRINT TAB(10);"dec";TAB(20);"hex";TAB(30);"binary"
- REPEAT
- REPEAT
- key$=INKEY$
- IF INP?(3)
- byte|=INP(3)
- IF byte|<>254
- IF TIMER-t%>200
- PRINT
- ENDIF
- t%=TIMER
- RSET byte$=STR$(byte|)
- RSET hex$=HEX$(byte|)
- RSET bin$=BIN$(byte|)
- PRINT TAB(10);byte$;TAB(20);hex$;TAB(30);bin$
- ENDIF
- ENDIF
- UNTIL key$=" " OR key$=CHR$(13)
- IF key$=CHR$(13)
- CLS
- ENDIF
- UNTIL key$=" "
- @all.midi.off
- REPEAT
- UNTIL INKEY$=""
- PRINT " (press any key)"
- ~INP(2)
- RETURN
-
-
- 13. MODEM
-
-
- INPAUX$
-
- With the command INPAUX$ the internal RS232-buffer is read and at the same
- time cleared. You can find the address of the input-buffer with :
- adr.in%=LPEEK(XBIOS(14,0))
- The output-buffer can be located with :
- adr.out%=LPEEK(XBIOS(14,0)+14)
-
-
- INP
-
- If you use INP(1) to read incoming bytes, you should always check with
- INP?(1) if the RS232-buffer contains data.
-
-
- Rsconf (XBIOS 15)
-
- With XBIOS 15 (Rsconf) you can change the RS232-parameters. A few
- baudrates :
- 0 - 19200 baud
- 1 - 9600 baud
- 4 - 2400 baud
- 7 - 1200 baud
- 9 - 300 baud
- 14 - 75 baud
- Use -1 for parameters you don't want to change. Due to a TOS-bug, you
- can't use 75 baud, because '14' results in 120 baud. Also, the old TOS
- (pre-Blitter age) can't handle hardware handshake with RTS/CTS-signals.
- Atari has released a bug-fix that should enable any TOS to use RTS/CTS.
- Software handshaking (XON/XOFF) functions properly. The default
- after power-up is no handshake protocol.
-
-
- 14. MOUSE
-
-
- Editor
-
- Sometimes the editor seems to freeze while the cursor is blinking rapidly.
- Just move the mouse and the editor comes alive again.
-
-
- Fileselector
-
- Sometimes the same blinking mouse appears after calling the Fileselector
- or an Alert-box. I've read somewhere this could be due to the combination
- of a VDI-function (for the mouse) and an AES-function (for Fileselector or
- Alert-box). GFA takes care of the first and GEM of the second, and
- sometimes this seems to result in a conflict.
-
-
- MOUSE
-
- If you repeatedly call a Procedure in which you test for a mouse-click,
- you should incorporate a short pause in the Procedure (e.g. PAUSE 5).
- Otherwise the Procedure might be called again while the user is still
- holding the button down. You could also wait until the user releases the
- button :
- REPEAT
- UNTIL MOUSEK=0 ! wait until button is released
-
- If you find it difficult to move the mouse accurately, you could use
- <Shift> <Alternate> <arrow> to move the mouse-cursor one pixel in the
- desired direction. If you press <Insert> as well, you can "drag" something
- accurately as if the left mouse-button was pressed.
-
- You can find the maximal x- and y-coordinates of the mouse with :
- x=DPEEK(&H9862)
- y=DPEEK(&H9864)
- But there's no guaranty you will find the coordinates there. Experiment
- with XBIOS 0 for a more reliable method. Don't ask me how.
-
- MOUSE returns negative coordinates if the mouse is to the left of or above
- the current window (or the origin that has been selected with CLIP
- OFFSET).
-
-
- SETMOUSE
-
- A mouseclick can be simulated with :
- SETMOUSE mx,my,mk
- If you try this with an Alert-button you have to move the mouse after-
- wards, or the button won't be selected. I don't know why, so I can't tell
- if this is a bug.
-
-
- DEFMOUSE
-
- You can use one of the many Public Domain mouse-editors to design your own
- mouse-mutant. But it's also easy to create a new mouse-cursor with the
- Procedure Initio.mouse1 :
- PROCEDURE initio.mouse1
- ' *** global : MOUSE1$
- RESTORE pattern.mouse1
- @make.mouse(mouse1$)
- pattern.mouse1:
- ' *** x,y,mode(0=normal;1=XOR),mask-colour,mouse-colour
- DATA 0,0,0,0,1
- ' *** mask-pattern (1 = pixel on , 0 = pixel off)
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- ' *** mouse-pattern
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- RETURN
- '
- PROCEDURE make.mouse(VAR m$)
- LOCAL x,y,mode,msk.color,mouse.color,n,msk%,mouse%,msk.pat$
- LOCAL mouse.pat$,msk$,mouse$,pat$
- CLR msk.pat$,mouse.pat$,pat$
- READ x,y,mode,msk.color,mouse.color
- FOR n=1 TO 16
- READ msk$
- msk%=VAL("&X"+msk$)
- msk.pat$=msk.pat$+MKI$(msk%)
- NEXT n
- FOR n=1 TO 16
- READ mouse$
- LET mouse%=VAL("&X"+mouse$)
- LET mouse.pat$=mouse.pat$+MKI$(mouse%)
- NEXT n
- m$=MKI$(x)+MKI$(y)+MKI$(mode)+MKI$(color.index(msk.color))
- m$=m$+MKI$(color.index(mouse.color))+msk.pat$+mouse.pat$
- RETURN
- The mask should be an exact copy of the mouse-pattern if you need a
- transparant mouse. Leave the mask empty (all '0') and the mouse will
- disappear behind objects on the screen. Fill the mask with '1' and the
- 16x16 mouse will always remain visible. Switch mask- and mouse-colour in
- the first DATA-line to create a "reverse" mouse. Or use any VDI colour-
- index that is available in the current resolution.
-
-
- 15. JOYSTICK
-
-
- STRIG and STICK
-
- Here is an example of the use of STRIG and STICK if your joystick is
- connected to Port 1 (your mouse is connected to Port 0) :
- STICK 1 ! joystick-mode (your mouse is now dead)
- REPEAT
- IF STRIG(1)
- joy=3
- ELSE
- joy=STICK(1)
- ENDIF
- ON joy GOSUB n,s,fire,w,nw,sw,dummy,e,ne,se
- PAUSE 5
- (...)
- UNTIL condition!
- STICK 0 ! back to mouse-mode
- You need eight Procedures for the eight possible directions (see below)
- and one Procedure for the Fire-button. The value 7 ('dummy') never occurs.
- If you don't touch the joystick, the value of 'joy' will be 0, and this
- means no Procedure will be called. A short pause is advisable, because
- GFA-Basic is too fast.
- 5 1 9
- \|/
- directions : 4-0-8
- /|\
- 6 2 10
-
- If you desperately need an active mouse while using the joystick, you
- could try the following "dirty" method :
- REPEAT
- IF MOUSEK=2
- joy=3
- ELSE
- joy=BYTE{&HE09} ! for TOS-version 1.0 !!
- ENDIF
- ON joy GOSUB n,s,fire,w,nw,sw,dummy,e,ne,se
- PAUSE 5
- UNTIL condition!
-
-
- 16. SOUND
-
-
- SOUND and WAVE
-
- After a SOUND-command, the sound sometimes continues in spite of the
- elapsed time. If the command is followed by another SOUND- or a WAVE-
- command, the time is handled correctly. This certainly sounds like a GFA-
- bug.
-
- The easiest way to stop all sound is :
- WAVE 0,0 ! turn all sound off
-
- Sound of a certain frequency can be produced with :
- SOUND ch,vol,#ROUND(125000/freq%),pause
-
- Although our ST is not famous for its brilliant sound, you can produce
- nice sound-effects with the simple commands SOUND and WAVE. Check out the
- Procedures Siren.sound, Tideli.sound, Bounce1.sound and Bounce2.sound to
- hear what I mean.
-
-
- Dosound (XBIOS 32)
-
- XBIOS 32 (Dosound) can be used to play music in a special format. I
- propose to use the extension 'X32' for song-files in this format. The
- operating system takes care of playing the music during interrupts (every
- 1/50th second). Take a look at the Procedures Play.song and Stop.song to
- see how you could use XBIOS 32 in your programs. You can even play a song
- continuously with the Procedure Play.cont.song. Temporarily stopping a
- song is possible with the Procedure Interrupt.song.
-
- If you use XBIOS 32 to play music, you are advised to switch the key-click
- off. Otherwise the music will stop as soon as the user presses a key.
-
- Once I discovered XBIOS 32 did not work during the initialization (mainly
- the filling of arrays) of a large program. I had converted the program
- from GFA-Basic 2.0 to 3.0, but I did not have the patience to find out
- what caused this problem.
-
- XBIOS 32 can also be used for sound-effects. I have developed the
- Procedure Initio.sound for building sound-strings from a few DATA-lines.
- I hereby declare this as the standard method for creating sound-strings.
- After @do.sound(sound$) you can hear the sound-effect. In the following
- example the sound-string bounce3$ is created :
- PROCEDURE initio.sound
- ' *** commands in DATA-lines :
- ' *** REG = 14 parameters for registers 0-13
- ' *** END = end of sound-string
- ' *** PAUSE = pause (followed by time in 1/50 seconds)
- ' *** VAR = decrease/increase tone : channel,start,+/-step,
- ' *** end-value
- '
- bounce3.sound:
- DATA REG,0,0,0,0,0,0,27,248,16,16,16,35,95,0
- DATA VAR,3,255,-1,116
- DATA PAUSE,255,END
- RESTORE bounce3.sound
- @sound.string(bounce3$)
- RETURN
- '
- PROCEDURE sound.string(VAR s$)
- LOCAL n,snd$,snd,channel,begin,step,end
- s$=""
- DO
- READ snd$
- snd$=UPPER$(snd$)
- EXIT IF snd$="END"
- IF snd$="REG"
- FOR n=0 TO 13
- READ snd
- s$=s$+CHR$(n)+CHR$(snd)
- NEXT n
- ENDIF
- IF snd$="PAUSE"
- READ snd
- s$=s$+CHR$(130)+CHR$(snd)
- ENDIF
- IF snd$="VAR"
- READ channel,begin,step,end
- s$=s$+CHR$(128)+CHR$(begin)+CHR$(129)+CHR$(channel)+CHR$(step)
- s$=s$+CHR$(end)
- ENDIF
- LOOP
- s$=s$+CHR$(255)+CHR$(0) ! terminator
- RETURN
- '
- PROCEDURE do.sound(sound$)
- VOID XBIOS(32,L:VARPTR(sound$))
- RETURN
-
-
- Samples
-
- From GFA-Basic you can surprise the user with a sampled sound. Examine the
- Procedures Sample, Load.sample and Play.sample to see how. You'll have to
- find suitable samples first. Look out for sound-effects and speech-
- samples. Personally, I just love the famous Perfect-sample.
-
-
- Speech
-
- Your ST can talk to you with a little help (STSPEECH.TOS). My current GFA-
- version (3.07) refuses to cooperate with the Procedures Initio.speech and
- Talk, but I have included these anyway. Perhaps you can discover the bug.
- In earlier versions both Procedures did work. A reset is necessary because
- EXEC 3 is used.
-
-
- Soundmachine
-
- You can play songs, created with Soundmachine (TommySoftware), from GFA-
- Basic. You'll need the Procedures Initio.soundmachine and Soundmachine,
- and a song-file. You'll probably wonder if it's really your ST that's
- playing the song. Soundmachine II is out, and looks even better. In this
- new version you can choose between playing songs with samples, or without
- samples (or samples for one of the three channels). You'll need the
- Procedure Sm.initio or Msm.initio and several others. Try to find the
- Public Domain demo-programs SAMSOUND.GFA, CHIPSND.GFA and SND_PLAY.GFA.
- End of commercial, continue with text.
-
-
- 17. PROGRAM DECISIONS
-
-
- IF ... ENDIF
-
- If the value of a certain variable must fall in the range min%-max%, you
- could program that as follows :
- IF n%>max%
- n%=max%
- ENDIF
- IF n%<min%
- n%=min%
- ENDIF
- In this case you could also use MAX and MIN :
- n%=MAX(MIN(n%,max%),min%)
-
- You probably test for two conditions by using :
- IF cond1! AND cond2!
- (...) ! both true
- ENDIF
- But separate testing is much faster :
- IF cond1!
- IF cond2!
- (...) ! both true
- ENDIF
- ENDIF
-
-
- SELECT
-
- Multiple 'ELSE IF'-constructions can be replaced by a 'SELECT'-
- construction. At each CASE you can use integers, strings or integer-
- variables (not string-variables). Only the first four bytes of a string
- can be used. The editor will not accept something like CASE "test2",
- only CASE "test".
-
-
-
- 18. PROGRAM LOOPS
-
-
- Calculations
-
- Try to remove all unnecessary calculations from loops, e.g. :
- FOR i=1 TO 1000
- x(i)=2*q*i
- NEXT i
- It's a better idea to calculate 2*q outside the loop :
- q2=q*2
- FOR i=1 TO 1000
- x(i)=q2*i
- NEXT i
-
- Always try to convert floating point variables to integers before entering
- a loop. Then you will be able to use the fast integer-operators. An
- obvious example would be a calculation with dollars (24.37) that could be
- replaced by a calculation with cents (2437). Use this method if you know
- the lowest possible value of the floating point variable (0.01 in this
- case) and then divide by this value. But watch out for rounding errors and
- integer-overflow.
-
- Powers of 2 can be calculated fast by setting a bit :
- x%=BSET(0,6) ! faster than x%=2^6
- And for the ultimate speed-freaks, multiplying with a power of 2 is
- slightly faster with SHL :
- y%=SHL(x%,3) ! faster than y%=MUL(x%,8)
- Of course there is no overflow-control if you use SHL (or MUL).
-
- Sometimes, calculations in a loop can be replaced by a look-up table :
- FOR i=1 TO 1000
- y%(i)=x|(i)^2
- NEXT i
- First, create a table of squares :
- DIM square%(255)
- FOR i=0 TO 255
- square%(i)=i*i
- NEXT i
- Then use this table in the loop :
- FOR i=1 TO 1000
- y%(i)=square%(x|(i))
- NEXT i
-
-
- FOR ... NEXT
-
- I use local variables in Procedures if possible. But if you intend to
- compile the program later, you should declare the counter in a FOR ...
- NEXT loop as a global variable. In the compiled program, the loop will be
- executed faster!
-
- If you use floating point count-variables in a FOR ... NEXT loop (or any
- other loop), you could encounter unexpected problems :
- FOR i#=0.1 TO 0.9 STEP 0.1
- PRINT i#
- NEXT i#
- You would expect 0.9 as the result of the last addition (0.8 + 0.1), but
- 0.9 is never printed! This is not a bug in GFA-Basic, but caused by the
- internal (binary) representation of floating point numbers. The last
- addition results in a number slightly larger than 0.9 and therefore the
- loop is left after printing 0.8 . If you insert the line
- i#=ROUND(i#,14)
- in the loop, you can solve this problem. But the best solution is to avoid
- floating point count-variables in loops. Integer count-variables are much
- faster. You could easily change the loop to :
- FOR i=1 TO 9
- PRINT USING "#.#";i/10
- NEXT i
- One more time: 'i' is a word-variable, because I use word-variables as
- the default for number-variables without postfix.
-
- If you use a floating point variable in a REPEAT UNTIL loop, you can avoid
- the rounding error by using the special operator '==' :
- i#=0
- REPEAT
- i#=i#+0.1
- PRINT i#
- UNTIL i#==0.9
- But you can't use the '=='-operator in a FOR ... NEXT loop.
-
- In the following two examples a byte-variable is used as the counter :
- FOR i|=5 DOWNTO -1
- PRINT i|
- NEXT i|
- '
- FOR i|=250 TO 256
- PRINT i|
- NEXT i|
- Of course, a byte-variable cannot have a value of -1 or 256. GFA does not
- abort with an error-message, but skips the loops. Not a true bug perhaps,
- but close.
-
-
- Loops
-
- Although you can use many different loops in GFA-Basic 3.0, there are
- basically only two varieties. You can first test a condition, and then
- either continue or leave the loop. Or you can first enter the loop, and
- then test a condition to decide if you are going to continue or leave.
-
- In an interpreted program the first choice is the fast FOR ... NEXT loop,
- then the (slower) REPEAT ... UNTIL loop and finally the (slowest) WHILE
- ... WEND loop. In a compiled program all loops are executed equally fast!
- If you use a DO ... LOOP, an EXIT IF condition will always take some extra
- time.
- Try to avoid a negative test in a loop, as this will take more time. E.g.
- replace :
- WHILE NOT condition!
- (...)
- WEND
- by the much faster :
- DO UNTIL condition!
- (...)
- LOOP
- Or similarly replace :
- REPEAT
- (...)
- UNTIL NOT condition!
- by the faster :
- DO
- (...)
- LOOP WHILE condition!
-
- Finally, you could combine the test of one condition at the start of the
- loop with the test of another condition at the end of the loop :
- DO UNTIL condition_1!
- (...)
- LOOP WHILE condition_2!
-
-
- 19. PROGRAM CONTROL
-
-
- GOSUB
-
- A Procedure can be called in one of the following ways :
- GOSUB proc
- @proc
- proc
- I prefer the second method, because this is spotted easily in a listing.
- Also, the same method can be used to call a function.
-
-
- ON BREAK GOSUB
-
- You can't stop a program if a recursively called function is executed (?).
-
- Use ON BREAK CONT to prevent calling the Break-Procedure twice. Nobody can
- release the <Control> <Shift> <Alternate> keys fast enough :
- ON BREAK GOSUB break
- (...)
- PROCEDURE break
- ON BREAK CONT
- (...)
- ON BREAK GOSUB break
- RETURN
- In this case the Break-Procedure is activated again before leaving the
- Procedure. Study the Standard Procedure Break (in one of the STANxxxx.LST-
- files) for an example of this method.
-
-
- ERROR
-
- You can simulate ERRORs with values from -127 to 127. For GFA-errors use
- values from 0 to 93, for bomb-errors 102 (2 bombs) to 109 (9 bombs) and
- for TOS-errors -1 to -67.
-
-
- EVERY and AFTER
-
- It's not possible to use EVERY and AFTER at the same time. Both commands
- don't work during a long PAUSE or DELAY (or any other command that takes a
- lot of time). You can only call Procedures without parameters. Don't make
- the Procedure too long, or it may be called while being processed!
-
- In a compiled program you have to incorporate '$I+ U+', or EVERY and AFTER
- can't be used.
-
-
- GOTO
-
- You can't use GOTO in a Procedure, a Function or a FOR ... NEXT loop.
-
-
- DELAY
-
- The DELAY-command does not operate correctly in version 3.07 of GFA-Basic.
- During DELAY a Break is impossible. A nastier bug is the appearance of the
- mouse-cursor during DELAY, even after HIDEM. You are advised to use PAUSE
- instead.
-
-
- CHAIN
-
- In GFA-Basic all variables and arrays are lost after CHAINing the next
- program. However, you could use the 160-byte buffer of the scrap-library
- to pass a short message to the next program :
- buffer$=SPACE$(160) ! 160 bytes maximum ??
- message$="this message was sent by the previous program"
- message$=message$+CHR$(0)
- LSET buffer$=message$
- r%=SCRP_WRITE(buffer$) ! r%=0 if error
- CHAIN file$
- Read the message with :
- buffer$=SPACE$(160)
- r%=SCRP_READ(buffer$)
- message$=CHAR{V:buffer$}
- The use of this buffer is completely illegal, but who cares if you don't
- use a scrap-library? Unfortunately the GFA-editor seems to think so too,
- so you should experiment a little before trusting this method.
-
-
- EXEC
-
- If you are going to run another program more than once, you'll have to use
- EXEC 3 :
- base%=EXEC(3,file$,"","") ! load, but don't start yet
- base$=STR$(base%)
- cmdl$=CHR$(LEN(base$)+1)+base$ ! create command line
- (...)
- r%=EXEC(4,"",cmdl$,"") ! now run it
- The variable r% contains a value returned by the program (or -39 if not
- enough memory was available). Repeat the last line if you want to run the
- loaded program again. Of course you should use EXEC 0 if you're going to
- run the program one time only. Read the paragraph 'RESERVE' if you are
- going to use EXEC 3.
-
- If you call a '*.PRG'-program with EXEC 0, you pass the null-string ("")
- as the command-line. You need the command-line only if you call a '*.TTP'-
- program. The command-line is converted to upper case and can't exceed 125
- bytes. The first byte of the command-line (usually) determines the length
- of the line, so the command-line can't contain more than 124 characters.
- You can use this in a TTP-program (compiled GFA-Basic program, extension
- changed to TTP), but it's easier to read the command-line with :
- cmdl$=CHAR{BASEPAGE+&H81}
-
-
- 20. GRAPHICS
-
-
- SETCOLOR and VSETCOLOR
-
- With commands like COLOR, DEFTEXT, DEFFILL, etc., you use a VDI colour-
- index. Unfortunately SETCOLOR uses a different table :
- VDI colour-index : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- SETCOLOR (Low rez) : 0 15 1 2 4 6 3 5 7 8 9 10 12 14 11 13
- SETCOLOR (Med rez) : 0 3 1 2
- From this table it follows you would have to use 'SETCOLOR 2,r,g,b' to
- change colour-index 3. By the way, all Line-A commands use the SETCOLOR-
- table as well! This is not a "bug", but a consequence of two different
- colour-tables that are used by GEMDOS and GEM. You are advised to use :
- VSETCOLOR index,r,g,b
- This index is exactly the same as the colour-index, so you would use
- 'VSETCOLOR 2,r,g,b' in order to change colour-index 2. If you like, you
- could use the hexadecimal 3-byte mix-value :
- VSETCOLOR index,&Hrgb
- But you won't like it at all, because this doesn't work properly. GFA-
- Basic swaps the r- and g-byte, so you would have to use :
- VSETCOLOR index,&Hbgr
- Better avoid this method, or you'll experience colour-changes if GFA
- corrects this bug in a future version.
-
- In High resolution you can invert the screen-colours with :
- VSETCOLOR 0,0 ! reverse High-screen (black background)
- VSETCOLOR 1,0 ! normal High-screen (black letters)
- An inverted screen is perhaps slightly less suitable for text, but
- graphics look superb.
-
- Colour-index 0 determines the colour of the background in Low and Medium
- resolution. This index also determines the colour of the border on your
- screen. You can change this colour, although you can't draw or PRINT on
- the screen-border of your colour monitor. The colour of all PRINTed text
- is determined by colour-index 1, unless you use the 'Esc b' command (read
- the paragraph 'PRINT' again if your long-term memory is too short) :
- VSETCOLOR 0,r,g,b ! change colour of background
- VSETCOLOR 1,r,g,b ! change colour of all PRINTed text
-
-
- Palette
-
- Before changing colours, you should always save the current palette. And
- do restore the old palette before the user exits the program. I hate
- programs that return to a pink or yellow desktop. You can store the
- palette either in an integer array or in a string, using XBIOS 7
- (Setcolor) :
-
- PROCEDURE save.palette
- LOCAL i
- ERASE old.palette%()
- DIM old.palette%(15)
- FOR i=0 TO 15
- old.palette%(i)=XBIOS(7,i,-1)
- NEXT i
- RETURN
- '
- PROCEDURE make.palette.string(VAR pal$)
- LOCAL n
- pal$=""
- FOR n=0 TO 15
- pal$=pal$+MKI$(XBIOS(7,n,-1))
- NEXT n
- RETURN
- The string-method is compatible with Degas. Restore the old palette with
- the corresponding Procedures :
- PROCEDURE restore.palette
- LOCAL i
- FOR i=0 TO 15
- VOID XBIOS(7,i,old.palette%(i))
- NEXT i
- RETURN
- '
- PROCEDURE change.palette(pal.string$)
- VOID XBIOS(6,L:VARPTR(pal.string$))
- RETURN
- You could also use the Standard Procedure Standard.low.colors or
- Standard.med.colors to restore the default palette. You can find these
- Procedures in the STANxxxx.LST-files.
-
- You can examine the rgb-value of a certain VDI colour-index with :
- PROCEDURE rgb.value(index,VAR rgb$)
- LOCAL col%
- col%=XBIOS(7,color.index(index),-1)
- rgb$=RIGHT$(HEX$(col%),3)
- RETURN
- The Standard Array color.index() is used to convert the VDI colour-index.
-
- A completely new palette for Medium resolution can be installed with :
- PROCEDURE new.med.colors
- LOCAL n,r,g,b,col$
- RESTORE med.new.col.data
- FOR n=0 TO 3
- READ col$
- r=VAL(LEFT$(col$))
- g=VAL(MID$(col$,2,1))
- b=VAL(RIGHT$(col$))
- VSETCOLOR n,r,g,b
- NEXT n
- med.new.col.data
- DATA 000,000,000,000
- RETURN
- You can show the current palette on the screen with the Procedure
- Palette.box :
- PROCEDURE palette.box(x,y,h,w)
- ' *** left upper corner of rectangle at x,y
- ' *** rectangle-height h; width of one colour-box w
- LOCAL arect.fill,fill.adr%,i,x1,x2
- x2=x+16*w+2
- COLOR black
- BOX x,y,x2,y+h
- arect.fill=-1
- f%=V:arect.fill
- IF low.res!
- FOR i=0 TO 15
- x1=ADD(SUCC(x),MUL(i,w))
- ARECT x1,SUCC(y),ADD(x1,w),PRED(ADD(y,h)),color.index(i),0,f%,0
- NEXT i
- ELSE IF med.res!
- FOR i=0 TO 3
- x1=ADD(SUCC(x),MUL(i,w))
- ARECT x1,SUCC(y),ADD(x1,w),PRED(ADD(y,h)),color.index(i),0,f%,0
- NEXT i
- ENDIF
- RETURN
-
- You can darken the screen by dimming all colours simultaneously with the
- Procedure Dim.colors :
- PROCEDURE dim.colors(reg1,reg2,val)
- ' *** dim colours from VDI colour-index reg1 to reg2 with val
- ' *** for val=1 colour 254 (rgb) will become 143
- LOCAL i,r,g,b
- FOR i=reg1 TO reg2
- @rgb.value(i,rgb$)
- r=MAX(PRED(VAL(LEFT$(rgb$))),0)
- g=MAX(PRED(VAL(MID$(rgb$,2,1))),0)
- b=MAX(PRED(VAL(RIGHT$(rgb$))),0)
- VSETCOLOR i,r,g,b
- NEXT i
- RETURN
-
- Nothing is impossible in GFA-Basic, even colour-cycling is easy with
- EVERY in the Procedure Color.cycle :
- PROCEDURE color.cycle(reg1,reg2,time)
- ' *** cycles colours from VDI colour-index reg1 to reg2
- ' *** global : COLOR.CYCLE! COL.REG1 COL.REG2
- IF NOT color.cycle!
- col.reg1=reg1
- col.reg2=reg2
- color.cycle!=TRUE
- EVERY time GOSUB cycle.once
- ELSE
- color.cycle!=FALSE
- EVERY STOP
- ENDIF
- RETURN
- '
- PROCEDURE cycle.once
- LOCAL col1%,col2%
- col1%=XBIOS(7,color.index(col.reg2),-1)
- FOR reg=col.reg1 TO PRED(col.reg2)
- col2%=XBIOS(7,color.index(reg),-1)
- ~XBIOS(7,color.index(reg),col1%)
- SWAP col1%,col2%
- NEXT reg
- ~XBIOS(7,color.index(col.reg2),col1%)
- RETURN
- Call the Procedure Color.cycle again to stop the colour-cycling.
-
-
- DEFMARK
-
- The point as mark-symbol (No. 1) cannot be enlarged. Other mark-symbols
- can be enlarged, but all lines in the symbol retain a width of one pixel.
- The size of a symbol must be a multiple of 11 plus 6: 0, 17, 28, 39, 50.
- For a value in between, the prior allowed size is chosen. Perhaps there is
- some magic hidden in the allowed sizes, or am I missing something?
-
-
- DEFFILL
-
- If you haven't defined your own Fill-pattern, the Atari-symbol will be
- used after DEFFILL 1,4,x. The desktop Fill-pattern is DEFFILL 1,2,4.
-
- The Fill-pattern string can consist of 16, 32 or 64 words (MKI$-format).
- Word 1 to 16 is needed for bitplane 0 (High resolution), word 17 to 32 for
- bitplane 1 (Medium resolution) and word 33 to 64 for the bitplanes 2 and 3
- (Low resolution). In all resolutions, the pattern occupies a rectangle of
- 16x16 pixels on the screen. The same 16x16 rectangle is also used for the
- mouse-cursor and sprites. You can always use a Fill-pattern in a lower
- resolution, e.g. a High-pattern in Medium or Low resolution, but not the
- other way around. Examine the three Procedures Initio.high.fill1,
- Initio.med.fill1 and Initio.low.fill1 to see how easy you can design your
- own Fill-patterns. There's gold in them thar Fills. You could surprise the
- user with a bomb-pattern :
- PROCEDURE initio.bomb.fill
- ' *** global : BOMB.FILL$
- RESTORE bomb.fill
- @make.high.fill(bomb.fill$)
- bomb.fill:
- DATA 0000011000000000
- DATA 0010100100000000
- DATA 0000000010000000
- DATA 0100100001000000
- DATA 0001000111110000
- DATA 0000000111110000
- DATA 0000011111111100
- DATA 0000111111111110
- DATA 0000110111111110
- DATA 0001111111111111
- DATA 0001111111101111
- DATA 0000111111101110
- DATA 0000111111011110
- DATA 0000011111111100
- DATA 0000001111111000
- DATA 0000000011100000
- RETURN
- '
- PROCEDURE make.high.fill(VAR fill$)
- LOCAL i,pat$,pat%
- CLR fill$
- FOR i=1 TO 16
- READ pat$
- pat%=VAL("&X"+pat$)
- fill$=fill$+MKI$(pat%)
- NEXT i
- RETURN
-
- Be careful, a screen filled with this pattern might provoke a heart-
- attack. If it doesn't, you could try the following dirty trick (High
- resolution only) with the Procedures Busy and Achtung :
- @busy ! looks like the computer is very busy
- ~INP(2) ! but nothing happens, until the user presses a key...
- @achtung
- PAUSE 500
- CLS
- PRINT " Thank you for your patience, I'm not busy anymore ..."
- PAUSE 150
-
- Many Fill-patterns are available as files. You can use these with
- something like Procedure Initio.fill1 :
- PROCEDURE initio.fill1(VAR pattern$)
- LOCAL bytes
- bytes=32 ! 32 bytes for High resolution
- ' *** load Fill-pattern (32 bytes for High resolution) here
- INLINE fill1%,32
- pattern$=STRING$(bytes,0)
- BMOVE fill1%,V:pattern$,bytes
- DEFFILL ,pattern$
- RETURN
-
- FILLing a screen with a pattern takes some time, especially in High
- resolution. Use the following method for almost immediate filling of the
- entire High resolution screen :
- PROCEDURE full.fill(fill%)
- ACLIP 1,0,0,639,399
- ARECT 0,0,639,399,1,0,fill%,15
- ACLIP 0,0,0,639,399
- RETURN
- Fill% is the address of a FILL-pattern (32 bytes). This very fast
- alternative Fill-method works in High resolution only.
-
-
- DEFLINE
-
- After 'DEFLINE ,n' all horizontal lines have a width of n pixels (n should
- be odd), except in Medium resolution. But if n is larger than 1, all
- vertical lines are n+2 pixels wide! I have trouble counting the pixels
- in Medium resolution. I think the width of horizontal lines is :
- n : 1 3 5 7 9
- width : 1 1 3 3 5 etc.
- Is this documented anywhere?
-
- You define your own Line-patterns by using a negative 16-bit value (from
- -&X1 to -&X1111111111111111). Each set bit corresponds with a pixel in the
- Line-pattern (High resolution). The highest bit (15) corresponds with the
- leftmost pixel of the pattern. Don't get confused if the editor changes
- the negative binary number you entered as a pattern. The editor uses a
- special notation for negative binary numbers.
-
- GFA-Basic represents integer numbers as binary strings of 32 bits. The
- most significant bit (31) determines the sign of the integer. If this bit
- is 0, the remaining 31 bits represent an "ordinary" positive number. But
- if the most significant bit is 1, the remainder is a negative number in
- 'two's complement' notation. I won't try to explain that. In any case, the
- next time you type -&X111 and a friend is watching you, don't blink your
- eyes, but casually remark "of course the editor converts this into two's
- complement notation". That's also the reason GFA-Basic can work with
- integers from -(2^31) to +(2^31)-1.
-
-
- DEFTEXT
-
- In some publications you can read about 'shadowed text' (style = 32), but
- unfortunately our GEM doesn't know this style. You can even find the mask
- for shadowed text with WORD{L~A+92}, but it's 0.
-
- I never succeeded in finding the current text-style with VDISYS 38
- (vqt_attributes). Either a bug in GEM or my mistake. I don't want to know,
- because the easy way is :
- txt.style=WORD{L~A+90}
- This could be important if you intend to use DEFTEXT in a Procedure, but
- would like to restore the original DEFTEXT-settings before leaving the
- Procedure.
-
- With DEFTEXT you can set the height of TEXT-letters. A letter occupies
- more space though, determined by the letter-box :
-
- letter-height letter-box system-font
- 4 6 x 6 icon
- 6 8 x 8 Medium & Low rez
- 13 8 x 16 High resolution
-
- The letter-height is the distance from Descent-Line to Ascent-Line, but
- the Bottom-Line and Top-Line lie at least one pixel lower/higher. The
- height of the letter-box is the distance from Bottom-Line to Top-Line.
-
- Most letters rest on the Base-Line, but letters with a descender (g,j,p,
- etc.) rest on the Descent-Line. If you are still with me, from top to
- bottom we have the following lines :
- Top-Line
- Ascent-Line
- Base-Line
- Descent-Line
- Bottom-Line
- Drop me a line if you don't understand this.
-
-
- GRAPHMODE
-
- If you draw a rectangle with BOX in GRAPHMODE 3 (Xor-mode), the pixel in
- the left upper corner is not drawn. Actually this pixel is drawn twice,
- and in GRAPHMODE 3 this means the pixel disappears. Use PLOT to draw this
- pixel :
- GRAPHMODE 3
- BOX x1,y1,x2,y2
- PLOT x1,y1 ! and fill the gap
-
- With PBOX in GRAPHMODE 3 you'll also get trouble in the same corner. Avoid
- this by using the command 'BOUNDARY 0' first :
- GRAPHMODE 3
- BOUNDARY 0
- PBOX 50,50,100,100
-
- GRAPHMODE 3 is especially useful if you make a temporary drawing. Draw the
- same picture a second time to restore the original screen. Examine Proce-
- dures like Rubber.line, Draw.box and Drag.box for examples of this method.
- The Procedure Rubber.line is used to draw a line from (x,y) to the mouse-
- cursor :
- PROCEDURE rubber.line(x,y,VAR x2,y2)
- LOCAL x1,y1,x2,y2,k
- GRAPHMODE 3
- DEFMOUSE 3
- SHOWM
- MOUSE x1,y1,k
- REPEAT ! main loop
- LINE x,y,x1,y1 ! draw line
- REPEAT
- MOUSE x2,y2,k
- UNTIL x2<>x1 OR y2<>y1 OR k>0 ! mouse moved
- LINE x,y,x1,y1 ! undraw line
- x1=x2
- y1=y2
- UNTIL k>0 ! mouse-click : ready (x2 and y2 returned)
- GRAPHMODE 1
- LINE x,y,x2,y2 ! this is it
- HIDEM
- DEFMOUSE 0
- PAUSE 10
- RETURN
-
- You could also use the 'GRAPHMODE 3'-method for animation, but the XBIOS 5
- (Setscreen) method is more suitable.
-
- Don't try to draw in GRAPHMODE 3 with a linewidth greater than 1 pixel.
- GEM will surprise you with some modern art if you can't resist the
- temptation.
-
- If you want to confirm a particular choice of the user, you can invert the
- relevant part of the screen with the Procedure Invert.block. Call this
- Procedure again with the same parameters to restore the original screen :
- PROCEDURE invert.block(x1,y1,x2,y2,color)
- GRAPHMODE 3
- DEFFILL color,1
- BOUNDARY 0
- PBOX x1,y1,x2,y2
- BOUNDARY 1
- GRAPHMODE 1
- RETURN
-
- You can 'grey out' an unavailable option on the screen with :
- PROCEDURE block.dimmer(x1,y1,x2,y2,color)
- GRAPHMODE 3
- DEFFILL color,2,2
- BOUNDARY 0
- PBOX x1,y1,x2,y2
- BOUNDARY 1
- GRAPHMODE 1
- RETURN
- Call this Procedure again to restore the screen.
-
- The entire (High resolution) screen can be dimmed with :
- PROCEDURE screen.dimmer
- ' *** global : DIMMER.SCREEN$ DIMMER.SWITCH!
- IF dimmer.switch!
- SPUT dimmer.screen$
- dimmer.switch!=FALSE
- ELSE
- SGET dimmer.screen$
- GRAPHMODE 4
- DEFFILL 1,2,4
- PBOX 0,0,639,399
- dimmer.switch!=TRUE
- ENDIF
- RETURN
- The screen will be restored if you call the Procedure again.
-
-
- PLOT and DRAW
-
- You can use both 'PLOT x,y' and 'DRAW x,y' to set a point on the screen.
- The size of the point can be changed :
- DEFLINE ,size,2,2 ! change size of points
- But the shapes you'll see don't look like points anymore, due to the same
- problem as described in the paragraph 'DEFLINE'. Use PCIRCLE for proper
- fat points.
-
-
- PCIRCLE
-
- With CLIP on, a PCIRCLE touching the upper screen-border is not filled
- properly in High resolution :
- CLIP 0,0,640,400
- PCIRCLE 0,0,50
- I don't know if we should blame GFA or GEM for not filling the two top-
- lines in the circle.
-
-
- CURVE
-
- With the command CURVE you can draw a Bezier-curve :
- CURVE x1,y1,x2,y2,x3,y3,x4,y4
- The Bezier-curve starts at (x1,y1) and ends at (x4,y4). The other two
- points act like little magnets. You can also use this command to draw a
- 'normal' curve between two points by letting the points (x3,y3) and
- (x4,y4) coincide. Try the following to see what I mean :
- GRAPHMODE 3
- MOUSE x2,y2,k
- DO
- CURVE 10,100,x2,y2,110,100,110,100 ! draw curve
- REPEAT
- MOUSE x,y,k
- UNTIL x<>x2 OR y<>y2
- CURVE 10,100,x2,y2,110,100,110,100 ! erase curve
- x2=x
- y2=y
- LOOP
- This method could be used to draw large letters.
-
-
- TEXT
-
- The coordinates used with TEXT determine the start of the Base-Line of the
- text. The descenders of letters like 'g', 'j', and 'p' lie below the Base-
- Line. This is especially important, not to say frustrating, if you use
- TEXT with an angle of 90, 180 or 270 degrees. The text rotates anticlock-
- wise around the TEXT-coordinates!
-
- If you intend to combine PRINTed text with TEXT, you probably will like
- the Procedure Text.at as the analogue of 'PRINT AT' :
- PROCEDURE text.at(c,l,t$)
- TEXT (c-1)*char.width,l*char.height+3*high.res!+2*(NOT high.res!),t$
- RETURN
-
- You can use TEXT to print "digital" numbers (ASCII-code 16-25) :
- FUNCTION digital$(number$)
- LOCAL dig$,i
- CLR dig$
- FOR i=1 TO LEN(number$)
- dig$=dig$+CHR$(BCLR(ASC(MID$(number$,i,1)),5))
- NEXT i
- RETURN dig$
- ENDFUNC
- Use this Function as follows :
- TEXT x,y,@digital$("1237")
-
-
- SPRITE
-
- You could design and save sprites in vitro with one of the many Sprite-
- editors that are available. Or you can use something like the Procedure
- Initio.sprite1 to create a sprite in vivo. Compare this Procedure also
- with the Procedure Initio.mouse1 :
- PROCEDURE initio.sprite1
- ' *** global : SPRITE1$
- RESTORE pattern.sprite1
- @make.sprite(sprite1$)
- pattern.sprite1:
- ' *** x,y,mode(0=normal;1=XOR),mask-colour,sprite-colour
- DATA 0,0,0,0,1
- ' *** mask-pattern (1 = pixel on , 0 = pixel off)
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- ' *** sprite-pattern
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- DATA 0000000000000000
- RETURN
- '
- PROCEDURE make.sprite(VAR s$)
- LOCAL x,y,mode,msk.color,spr.color,n,msk%,spr%,msk.pat$,spr.pat$
- LOCAL msk$,spr$,pat$
- CLR msk.pat$,spr.pat$,pat$
- READ x,y,mode,msk.color,spr.color
- FOR n=1 TO 16
- READ msk$
- msk%=VAL("&X"+msk$)
- msk.pat$=msk.pat$+MKI$(msk%)
- NEXT n
- FOR n=1 TO 16
- READ spr$
- spr%=VAL("&X"+spr$)
- spr.pat$=spr.pat$+MKI$(spr%)
- NEXT n
- FOR n=1 TO 16
- pat$=pat$+MID$(msk.pat$,n*2-1,2)+MID$(spr.pat$,n*2-1,2)
- NEXT n
- s$=MKI$(x)+MKI$(y)+MKI$(mode)+MKI$(color.index(msk.color))
- s$=s$+MKI$(color.index(spr.color))+pat$
- RETURN
- The mask should be an exact copy of the sprite-pattern if you need a
- transparant sprite. Leave the mask empty (all '0') and the sprite will
- disappear behind objects on the screen. Fill the mask with '1' and the
- 16x16 sprite will always remain visible. Switch mask- and sprite-colour in
- the first DATA-line to create a "reverse" sprite. Or use any VDI colour-
- index that is available in the current resolution.
-
- If you put a sprite on the screen, the background (16x16 pixels) is
- temporarily saved. Using more than one sprite simultaneously, it is
- essential you remove sprites in reverse order. This is necessary because a
- sprite could overlap another sprite. Removing the top sprite first ensures
- that the original background will reappear after removing the first
- sprite, e.g. :
-
- DO
- (...)
- SPRITE s2$ ! remove sprites...
- SPRITE s1$
- VSYNC ! prevents blinking, but slows down
- SPRITE s1$,x1,y1 ! draw sprites...
- SPRITE s2$,x2,y2
- (...)
- LOOP
-
-
- VQT_EXTENT
-
- The function VQT_EXTENT can be used if you would like to draw a rectangle
- around a text-string :
- ~VQT_EXTENT(txt$,x1,y1,x2,y2,x3,y3,x4,y4)
- The coordinates of the four corners depend on the angle of the text (0,
- 90, 180 or 270 degrees) and of course on the size of the text. The point
- (x1,y1) is the lower left corner of the imaginary rectangle around the
- text and the other points are arranged anticlockwise around the text-
- string. Because the text rotates around the TEXT-coordinates (start of the
- Base-Line), it will take some trial and error to determine the correct
- position of the rectangle if the angle is not 0 degrees. In the following
- table you'll find the "true" origin of the rectangle, the width and the
- height of the rectangle, and also the actual position of the lower left
- corner of the text-block (x1,y1) :
- angle position (x1,y1) origin width height
- 0 lower left x1,y1 x2 y4
- 900 lower right x4,y4 x1 y3
- 1800 upper right x3,y3 x4 y2
- 2700 upper left x2,y2 x3 x4
- The coordinates of the origin are (0,0), so with an angle of 0 degrees
- both x1 and y1 are 0. The rectangle rests on the x-axis, while the left
- side coincides with the y-axis. This is a "mathematical" y-axis, not a
- "screen" y-axis. This means you go upwards for positive y-values. For an
- angle of 0 degrees the coordinates will be :
- (x4,y4). .(x3,y3)
- . TEXTBLOCK .
- (x1,y1) (x2,y2)
-
- If you understand the table, you should be surprised by the height 'x4'
- instead of 'y1' at an angle of 270 degrees. I think I discovered a bug in
- GEM here. Correct GEM by changing the following variables if an angle of
- 270 degrees is used :
- y1=x4
- SWAP x4,y4
- Now, the height is 'y1' as you suspected. Clever, aren't we? I have not
- been able to confirm my discovery. None of my reference-books mention the
- bug.
-
-
- Line-A
-
- The Line-A commands are faster than the corresponding VDI-commands in GFA-
- Basic. The difference should be even greater after loading GDOS (?). In
- the following table you can find how many times faster the Line-A command
- is :
- PSET / PLOT = 3
- PTST / POINT = 2
- HLINE / LINE = 2
- ARECT / PBOX = 1.5
- The syntax of Line-A commands is more complicated, but that's no problem
- for us GFA-experts. Line-A commands use the 'SETCOLOR-index', so you'll
- probably need the Standard Array color.index().
-
- HLINE
-
- An additional advantage of the commands HLINE, ARECT and APOLY is that you
- don't have to change the DEFFILL-parameters in the main program. For solid
- horizontal lines, use :
- pattern=-1
- adr%=V:pattern
- HLINE x1,y,x2,color,mode,adr%,0
- You can't use &X1111111111111111 (16 bits) for the pattern, because bit 15
- of a word-variable is a flag for a negative number. Yes, that's why the
- largest positive word is 2^15 - 1 (32767). The solution to this little
- problem is to assign -1 to the word-variable. You have my word, now all 16
- bits are 1. Use BIN$ if you don't believe me.
-
- For very complicated patterns you could use a word-array :
- DIM pattern(i)
- adr%=V:pattern(0)
- (...) ! put fill-pattern in pattern(0) to pattern(i)
- HLINE x1,y,x2,color,mode,adr%,i
-
-
- ACHAR and ATEXT
-
- It's difficult to combine the Line-A commands ACHAR and ATEXT with TEXT.
- The coordinates used with ACHAR and ATEXT determine the position of the
- left upper corner of the (first) letter-box. That's the Top-Line, not the
- Base-Line.
-
- You can't use the text-style underlined (8) with ACHAR and ATEXT. Probably
- a GFA-bug.
-
-
- GET and PUT
-
- You could save a rectangular part of the screen as follows :
- GET x1,y1,x2,y2,pic$
- BSAVE file$,V:pic$,LEN(pic$) ! use the extension PUT in the filename
-
- Later, you could put the saved picture back on the screen with :
- OPEN "I",#1,file$
- LET bytes%=LOF(#1) ! how many bytes needed?
- CLOSE #1
- picture$=SPACE$(bytes%) ! reserve some space,
- BLOAD file$,V:picture$ ! load the picture
- PUT x,y,picture$ ! and look at it
-
- The Procedures Message, Warning, Message.on and Message.off use GET and
- PUT to save and later restore the part of the screen that is used for
- text.
-
- A GET-string starts with three words for width, height and number of
- bitplanes. The number of bitplanes is determined by the resolution: 1 for
- High, 2 for Medium and 4 for Low. After these three words follows the
- actual picture as a list of words. As the picture-width is not necessarily
- a multiple of 16, any bits beyond the right border will be ignored by the
- PUT-command.
-
- Here is the connection between GRAPHMODE and PUT-mode :
- GRAPHMODE PUT-mode
- 1 3 (default)
- 2 7
- 3 6
- 4 13
-
- I have encountered a few programs in GFA-Basic 2.0 where PUT was used
- just outside the screen. In GFA-Basic 3.0 the program didn't work. The
- same occurred in a program where a picture was BLOADed a few bytes before
- the screen-RAM. I don't understand why GFA-Basic 3.0 doesn't accept this,
- as there is some unused space there (read the paragraph 'RAM'), but I've
- learned to correct this when I convert a program from GFA-Basic 2.0 to
- version 3.0.
-
-
- Degas-Pictures
-
- A Degas picture-file contains not only the actual picture (same format as
- SGET-picture), but also the colour-palette. Use the Procedure Show.degas
- to load and show a Degas-picture :
- PROCEDURE show.degas(degas$)
- LOCAL degas.picture$,degas.picture%,degas.palette$
- LOCAL degas.palette%
- degas.picture$=SPACE$(32000)
- degas.picture%=VARPTR(degas.picture$)
- degas.palette$=SPACE$(32)
- degas.palette%=VARPTR(degas.palette$)
- OPEN "I",#90,degas$
- SEEK #90,2 ! skip resolution
- BGET #90,degas.palette%,32 ! load palette of picture
- SEEK #90,34
- BGET #90,degas.picture%,32000 ! load actual picture
- CLOSE #90
- ~XBIOS(6,L:degas.palette%) ! change palette
- SPUT degas.picture$ ! show the picture
- RETURN
-
- The original Degas-files have a length of 32034 bytes :
- 1 word - resolution
- 16 words - palette
- 16000 words - picture data
- You can use BTST to check the resolution (bit 0 = Low, bit 1 = Medium, bit
- 2 = High), but you could also look at the extension of the filename
- (PI1/PI2/PI3 for Low/Medium/High). In the second Degas-version (Degas
- Elite), 16 words for "colour-animation" can be added after the picture
- data.
- A Degas Elite picture can (and really should!) be saved in a compressed
- format. The extensions PC1/PC2/PC3 are used for Low/Medium/High
- resolution. Also, the highest bit of the resolution-word is set as a flag
- for a compressed picture. With the Procedure Show.comp.degas you can load
- and show a compressed Degas-picture.
-
-
- Neochrome-Pictures
-
- Sometimes the "Neochrome"-format is used for pictures (32128 bytes) :
- 1 integer - resolution (0/1/2 for Low/Medium/High)
- 16 words - palette
- 12 bytes - filename (nnnnnnnn.eee)
- 4 bytes + 1 word - colour animation data
- 18 integers - reserved
- 16000 words - picture data
-
-
- VSYNC
-
- The VSYNC-command is useful if you want to prevent irritating blinking
- during animation. Always VSYNC before drawing a new picture in an
- animation sequence (including SPRITE-animation). The program is slowed
- down of course, because it waits for a vertical blank interrupt before
- starting to draw. But it looks much nicer.
-
-
- Scroll
-
- With BMOVE and RC_COPY you can accomplish pretty smooth scrolling. GET/PUT
- is too slow, and only works on the logical screen. BITBLT is more
- flexible, but also more complicated. And not faster (?). Study the
- Procedures Scroll.up and Scroll.down to see how you could scroll the
- entire screen up or down :
-
- PROCEDURE scroll.up(scroll.lines,scroll.color)
- LOCAL n,bytes,move.bytes,source%
- IF high.res!
- LET bytes=80*scroll.lines
- ELSE
- LET bytes=160*scroll.lines
- ENDIF
- move.bytes=32000-bytes
- source%=physbase%+bytes
- VSYNC
- BMOVE source%,physbase%,move.bytes
- DEFFILL scroll.color
- PBOX 0,scrn.y.max-scroll.lines+1,scrn.x.max,scrn.y.max
- FOR n=1 TO DIV(scrn.y.max,scroll.lines)
- VSYNC
- BMOVE source%,physbase%,move.bytes
- NEXT n
- RETURN
- Can anybody explain the interference lines that sometimes appear during
- the scrolling?
-
- Several fade-over effects can be found in the Procedures Up.scroll,
- Slider.scroll, etc. Most Procedures can only be used in High resolution.
-
- For scrolling of one or more text-lines you could use the Procedures
- Scroll.text.up and Scroll.text.down :
- PROCEDURE scroll.text.up(begin,end)
- LOCAL screen%,sx,sy,w,h,dx,dy
- IF begin>1 AND end>=begin
- screen%=XBIOS(3) ! logical screen
- sx=0
- sy=(begin-1)*char.height
- w=scrn.x.max
- h=(end-begin+1)*char.height
- dx=0
- dy=sy-char.height
- RC_COPY screen%,sx,sy,w,h TO screen%,dx,dy
- ELSE
- PRINT bel$;
- ENDIF
- RETURN
- This method is also used in the Procedure Debug.
-
-
- ACLIP
-
- Line-A commands are 'CLIP-sensitive', so you should always use an appro-
- priate ACLIP-command before a Line-A command. The following Line-A
- commands are not influenced by ACLIP : ALINE, HLINE, PSET, PTST and
- BITBLT.
-
-
- Blitter
-
- The Blitter-TOS (1987) allows you to switch the Blitter on/off. I couldn't
- test the following Procedure, because I don't have a Blitter. But if I
- understand the function XBIOS 64 (Blitmode) correctly, you could switch
- the Blitter on and off from GFA-Basic :
- PROCEDURE blitter(switch!)
- LOCAL status
- status=XBIOS(64,-1)
- IF BTST(status,1) ! Blitter available?
- IF switch!
- status=BSET(status,0) ! Blitter on
- ELSE
- status=BCLR(status,0) ! Blitter off
- ENDIF
- ~XBIOS(64,status) ! do it
- ENDIF
- RETURN
-
- By the way, Line A commands do not use the Blitter. The Blitter-chip
- contains a hardware-routine that replaces the Line A BitBlt-function
- (BITBLT in GFA-Basic). All Mega ST's have a Blitter installed.
-
-
- 21. EVENTS
-
-
- MENU()
-
- There is no easy way to test in a program if an accessory has been
- selected by the user. MENU(1) looks promising, but the value 40 (select
- accessory) or 41 (close accessory) is only sent to the accessory! It
- would have been nice to be able to determine if an accessory has been
- closed, because GEM will clear the accessory-window and will fill the
- space with the desktop-pattern. No easy solution for this one, sorry. The
- best idea probably is to test frequently with 'IF MENU(1)=20' if a redraw
- is necessary, e.g. :
- ON MENU MESSAGE GOSUB redraw
- (...)
- PROCEDURE redraw
- IF MENU(1)=20
- (...) ! redraw screen
- ENDIF
- RETURN
- This method only works if you have opened a window.
-
-
- ON MENU BUTTON
-
- The syntax for ON MENU BUTTON is :
- ON MENU BUTTON clicks,button,event GOSUB proc
- For both 'button' and 'event' you can use the numbers 0-3. The variable
- 'clicks' stands for the maximal number of clicks you want to register. If
- you choose '2', the Procedure will be called if the user clicks once or
- twice :
- ON MENU BUTTON 2,1,1 GOSUB proc
- It's not possible to wait for a double-click, unless the progam is really
- waiting, and not doing anything else :
- SELECT EVNT_BUTTON(2,1,1)
- CASE 1
- ' clicked once
- CASE 2
- ' clicked twice
- ENDSELECT
- But you can't combine this with an ON MENU loop.
-
- If you use the described method :
- ON MENU BUTTON 2,1,1 GOSUB proc
- you could use MENU(15) in the called Procedure to check if the user
- clicked twice. The same Procedure would be called after a single click,
- but you could ignore that. Fasten your seatbelts now. If you run such a
- program the first time, a double click is not registered in MENU(15). If
- you suspect a bug and run the program again, MENU(15) works all right.
- Nasty.
-
- Another bug, but this time a GEM-bug (I think), after :
- ON MENU BUTTON 1,2,2 GOSUB proc
- The Procedure is called immediately, whether the right mouse-button was
- pressed or not.
-
- If you want to switch ON MENU BUTTON temporarily off, use :
- ON MENU BUTTON clicks,button,event GOSUB dummy
- The Procedure Dummy should be empty. Use the same method to switch other
- ON MENU commands temporarily off.
-
-
- ON MENU IBOX
-
- You can define two independent rectangles with ON MENU IBOX and/or ON MENU
- OBOX, either :
- - one IBOX and one OBOX
- - two IBOXes
- - two OBOXes
-
-
- 22. PULLDOWN MENU
-
-
- OPENW 0
-
- Even if you don't need a window, you could 'OPENW 0' if you use a
- pulldown menu. The top line (y-coordinates 0 to 18 in High resolution,
- that's where your menu is) is now protected against accidental drawing.
- After 'OPENW 0' 19 is always added to the y-coordinate, so with 'PLOT 0,0'
- the point is actually drawn at (0,19).
-
-
- Desk-submenu
-
- The first submenu in a pulldown menu should be the Desk-submenu ('Desk'),
- usually with the following lay-out :
- Info
- ------------
- Accessory 1
- Accessory 2
- (...)
- If the user chooses the Info-item, you should show some information about
- the program. The AES takes care of the accessory-items, you simply use
- '1,2,3,4,5,6' in the corresponding DATA-line. If you use '-,-,-,-,-,-' the
- user won't be able to choose an accessory from your program, but all
- loaded accessories still occupy memory.
-
-
- File-submenu
-
- Most pulldown-menu's contain a File-submenu ('File') as the second
- submenu. The following lay-out is more or less standard :
- New file ^N
- Open file ... ^O
- -----------------
- Close ^C
- Save ^S
- Save as ... ^M
- Abort ^A
- -----------------
- Quit ^Q
- With '...' you announce that further input from the user will be
- requested. If at all possible, you should offer optional keyboard-
- alternatives for the experienced user. With '^N' you remind the user of
- the <Control> <N> alternative. The character with ASCII-code 7 is used as
- the symbol for <Alternate>. By general agreement, the Quit-choice always
- is the last item of the File-submenu.
-
- By the way, never leave the last (rightmost) submenu without options, e.g.
- during development of a program. There must be at least one option in the
- last submenu, or it's reset-time again.
-
-
- 23. WINDOWS
-
-
- GFA-windows
-
- You'll notice that this chapter is rather short. This reflects my
- reservations about the use of windows. I know very few programs that use
- windows sensibly. For these programs GEM-windows indeed are a blessing.
- But most programs are better off without windows. GEM just slows the
- screen-output down. Cover your TOS-screen with windows only if you really
- need them.
-
- GFA-Basic has four "easy" windows for not too complicated jobs. Draw an
- imaginary cross on the screen. The intersection of the two lines is
- determined by the coordinates in 'OPENW n,x,y'. If you show more than one
- window on the screen, you should realize that resizing one window auto-
- matically changes the size of the other three windows as well (remember
- the cross?). Use the AES window-commands if you need independent windows.
-
- The four GFA-windows reserve the top line for a pulldown menu. If you use
- your own AES-windows, you should protect the top line yourself, e.g. with
- 'OPENW 0'.
-
- A standard-method for the use of GFA-windows looks like this :
- TITLEW #1," title " ! automatically centered
- INFOW #1,"information" ! left justified
- OPENW 1 ! or use FULLW #1
- CLEARW 1
- (...)
- CLOSEW 1
- CLOSEW 0
- I don't know how to use '#' properly. The editor does not accept '#' in
- 'OPEN #1', you have to use 'OPENW 1'. If you use FULLW instead of OPENW,
- you have to use 'FULLW #1'. In this case the '#' has to be used, or the
- command doesn't work at all! The GFA-editor always inserts a '#' after
- TITLEW and INFOW, even if you didn't type one. What the # is going on?
-
-
- CLOSEW
-
- If you have opened a window in your program, always use 'CLOSEW 0' before
- returning to the editor. If you don't, you can't work normally in Direct
- Mode. If you did forget, you can type 'CLOSEW 0' in Direct Mode and
- everything works fine again.
-
- If you use the AES window-commands, always call WIND_CLOSE(handle) before
- WIND_DELETE(handle).
-
-
- TITLEW
-
- You can clear a title with :
- TITLEW #n," "
- Don't use "" instead of " ", or you won't be able to move the window
- afterwards!
-
-
- CLEARW
-
- After 'CLEARW #n' all visible areas of the window are cleared, without
- activating the window. GFA uses WIND_UPDATE and WIND_GET for this command.
- 'CLEARW n' both clears and activates the window.
-
-
- 24. AES-LIBRARY
-
-
- ALERT
-
- If you need an empty line in an Alert-box, use :
- ALERT,3,"...| |...",1,"...",k
- Note the space between the two vertical rules.
-
- GFA-Basic allows 4 lines of 30 characters (High/Medium rez) if you use
- ALERT, but with FORM_ALERT you can use 5 lines. In both cases you can use
- not more than 3 buttons, each at most 8 characters (High/Medium rez) wide:
- m$=" line 1 | line 2 | line 3 | line 4 "
- ALERT 3,m$,1," OK ",k
- '
- m$="[3][ line 1 | line 2 | line 3 | line 4 | line 5 ][ OK ]"
- k=FORM_ALERT(1,m$)
-
- In Low resolution you can use only half the number of characters you use
- in High/Medium resolution.
-
- If some characters are not visible in a button, try broadening the Alert-
- box by adding spaces to the widest text-line.
-
- If you have pressed the left mouse-button on the very spot where an Alert-
- button is about to appear, something goes wrong. GEM appears to remember
- your last mouse-click, and erroneously assumes you pressed the button
- after the Alert-box appeared. GEM only selects the button if the mouse-
- click occurred in the exact area of the Alert-button. To avoid this
- problem you should make sure the user has released the mouse-button before
- you call the Alert-box :
- REPEAT
- UNTIL MOUSEK=0 ! wait until mouse released
-
- By the way, the AES uses an 8K buffer to save the part of the screen where
- the Alert-box appears. Ditto for a menu.
-
-
- SHEL_GET and SHEL_PUT
-
- GFA-Basic is run from a 'Shell-Program', usually the Desktop. In that case
- the file DESKTOP.INF can be found in the Environment-Buffer. You can
- examine this file by transferring it to a string :
- d$=STRING$(1024,0)
- r%=SHEL_GET(1024,d$)
- PRINTing this string is much easier than using a disk-editor to examine
- DESKTOP.INF.
-
- After changing the string, you could put it back in the buffer with :
- r%=SHEL_PUT(1024,d$)
- This way you could change the lay-out of the desktop. If you change the
- string, you should know that the Desktop recognizes the end of DESKTOP.INF
- by the byte &H1A. So don't forget to put CHR$(26) at the end. If you want
- to save the new buffer, try :
- OPEN "O",#1,"\DESKTOP.INF"
- PRINT #1,LEFT$(d$,INSTR(d$,CHR$(26)))
- CLOSE #1
-
-
-
-
-
-
- Is that all there is to tell about the AES-library? Certainly not, so at
- this point you will probably be bitterly disappointed. I avoid the AES-
- Library whenever I can. Anyway, this is a subject that is thoroughly
- covered in most books about GFA-Basic 3.0. Everyone is entitled to his own
- opinion about the usefulness of RSC-files and other exotic subjects.
- Better still, write this chapter yourself. And the same to you too!
-
-
- 25. GFAXPERT-FILES
-
-
- Take your time to read this chapter carefully, before using the GFAXPERT-
- Procedures or programs. The paragraph 'STANxxxx.LST' is essential reading.
- Don't forget to read the 'small print' in the last paragraph.
-
-
- GFAXPERT.DOC
-
- You're reading it.
-
-
- GFAXPERT.LIB
-
- This folder (in GFAXPRT2.ARC for downloaders) contains a large collection
- of Procedures in several LST-files. Each LST-file contains one or more
- folded Procedures. Most Procedures are also listed in this text, or are at
- least mentioned. I suggest you Llist all the LST-files with unfolded
- Procedures for easy reference. You could also Llist all LST-files again
- with folded Procedures, so you will be able to locate a Procedure quickly.
-
- Always read the comment-lines (' ***) in a Procedure before using it. You
- will find there if other Procedures are used, or Standard Globals (see
- paragraph 'STANxxxx.LST'). Sometimes a Procedure returns a global
- variable. Most variables are declared as LOCAL. And do read the relevant
- chapter of this text before using a Procedure.
-
- GFA has released a library of graphics- and sound-routines. I am curious
- about the quality of these routines, but I certainly do not intend to pay
- DM 148.- for the library. My advice would be to use the library
- GFAXPERT.LIB and pay DM 148.- to me.
-
-
- INLINE
-
- The INLINE-folder (in GFAXPRT2.ARC for downloaders) contains INLINE-files
- that you will have to load after Merging certain Procedures. This is
- clearly indicated in such Procedures.
-
-
- STANxxxx.LST
-
- Before writing a program, I decide in which resolution the program will
- run. Then I Merge the corresponding STANxxx.LST-file (in the folder
- GFAXPERT.LIB) and use that as the standard framework for my program :
- STANHIGH.LST - High resolution
- STANMED.LST - Medium resolution
- STANLOW.LST - Low resolution
- STANHIME.LST - High or Medium resolution
- STANALL.LST - all resolutions
- After deleting the first two lines and entering the name of the program
- (e.g. TEST.GFA), I Save the program as AAPROG.GFA in the Procedure-
- library. In this folder I have a few LST-files ready for easy Merging of
- Procedures into the program (AABLOCK1.LST, AABLOCK2.LST, etc.).
-
- Before you continue, you should Llist the five STANxxxx.LST-files. Merge
- STANHIGH.LST, unfold all Procedures, then Llist. In the other files you
- could restrict unfolding to the Procedure Initio (and perhaps the
- Procedures xxx.mode and Standard.xxx.colors). I'll wait until you have the
- listings of the STAN-files in front of you...
-
- Right, first I'll discuss STANHIGH.LST thoroughly. Later I'll point out
- some important features in the other STAN-files. You will not become an
- expert in structured programming immediately, but using the STAN-files
- should help.
-
- (1) The first line ('STANHIGH.LST') is there to remind you how to 'Save,A'
- this file after you have changed it. Delete it if you are going to develop
- a new program.
-
- (2) Enter the name of your new program (e.g. TEST.GFA) and immediately
- save the program as AAPROG.GFA in the Procedure-library.
-
- (3) Word-variables are defined as the default.
-
- (4) The Procedure Initio is called. In this Procedure the current
- resolution is checked, and after that, a few important global variables
- are defined (Standard Globals). The following Standard Globals are defined
- (read the comments in the listing for more information) :
- high.res! scrn.col.max return$
- scrn.lin.max esc$
- default.path$ help$
- white undo$
- physbase% black
- logbase% interpreter$
- on! run.only$
- scrn.x.max off! start.gfa$
- scrn.y.max start.prg$
- bel$
- char.width
- char.height
- Also, the Standard Array color.index() is created, although you'll only
- need it for a few Procedures (e.g. Initio.sprite1).
-
- (5) The Procedure Title.screen is not activated yet. You'll probably want
- to change that Procedure.
-
- (6) A normal <Break> should be possible while developing a program. In the
- finished program you could activate the Procedure Break, or delete it. Be
- very careful with <Break> if the program uses RESERVE or has changed the
- address of the physical/logical screen.
-
- (7) The main program usually is not much more than a list of Procedure-
- calls, e.g. :
- @start.game
- @play.game
- @score
- (8) Try to leave the program by calling the Procedure Exit. During
- development it's more convenient to leave with 'EDIT'.
-
- (9) Two Standard Functions are defined: Center$ for centering text and
- Rev$ for PRINTing reverse. The last function uses VT52-codes, so use it on
- the TOS-screen only.
-
- (10) The Standard Procedure High.mode (called from Initio) checks the
- current resolution and aborts with an appropriate message if the program
- is run in the wrong resolution.
-
- (11) The Standard Procedure Get.path (called from Initio) returns the
- current path. Using the interpreter, GEMDOS returns the path of the
- interpreter (e.g. 'A:\'), not of the running program! That's why I use
- CHDRIVE + CHDIR in the shell-programs. In that case the Standard Global
- default.path$ does contain the path of the running GFA-program. If you
- develop the program, you should use CHDRIVE/CHDIR in Direct Mode if
- necessary. I am not happy with this method, but I know no other solution
- for GFA-programs. If I don't use this method, I always define the path in
- the Initiation-part, e.g. :
- path$="A:\GAMES\" ! where are the data-files?
- Now another GFA-user only has to change the path and the program can find
- the necessary files. For owners of the Run-Only interpreter you should
- describe the proper configuration in a READ.ME-file. With compiled GFA-
- programs there is no problem, because GEMDOS will return the path of the
- running program.
-
- (12) I like to begin every program with a title-screen. Change the
- Standard Procedure Title.screen, or delete it if you don't like title-
- screens in your programs.
-
- (13) The Standard Procedure Return is used by Title.screen.
-
- (14) The Standard Procedure Break can be deleted if you don't need it.
- Don't use 'ON BREAK CONT' in your program, unless you have a very good
- reason to do so. Note that I have made it possible to use <Break> the
- normal way if the user chooses <CONT> while pressing the <Break>-
- combination.
-
- (15) The Standard Procedure Exit should always be used. This Procedure
- tries to go back to one of the shell-programs. If that's impossible, the
- Procedure decides to end with 'EDIT' or 'SYSTEM'. Is it possible to test
- in a program if it is run by the interpreter or if it is a compiled
- program? If the answer is yes, this Procedure could be improved.
-
- (16) Other Procedures can be inserted after '*** Procedures ***'. Merge
- Procedures from the library GFAXPERT.LIB (or your own library) here. I use
- the following method :
- - New, so memory is clear
- - Merge relevant LST-file from library
- - choose (folded) Procedure and Write as block to AABLOCKx.LST
- - repeat previous steps for other Procedure(s)
- - Load AAPROG.GFA
- - Merge AABLOCKx.LST at appropriate position(s)
- - Save program (press <Return> in Fileselector)
- Of course, you'll have to write a few Procedures from scratch. Before you
- know it, you'll have reached The End. It's so easy to write a program in
- GFA-Basic 3.0, that I actually enjoy programming.
-
- (17) Debugging is perhaps less fun than programming. Merge the Procedure
- Debug temporarily in your program if you need some help. And do save your
- program regularly! Fall back to the program AAPROG.BAK if your latest
- improvements were fatal. If you are completely satisfied, save the program
- under its proper name (TEST.GFA). Also save a back-up on another disk,
- just in case something terrible should happen to your original program.
-
- (18) In STANALL.LST you'll notice in the Procedure Initio that I always
- start with the default palette (Procedures Standard.med.colors and
- Standard.low.colors). New Standard Globals in STANALL.LST are :
- red med.res!
- green low.res!
- The Standard Array color.index() is very important in Medium or Low
- resolution.
-
- (19) In STANHIME.LST (my favourite) the only important difference is the
- Procedure High.med.mode, where the current resolution is checked.
-
- (20) In STANLOW.LST all 16 default-colours are now defined as Standard
- Globals :
- white blue grey l.purple
- black d.blue l.black d.purple
- red brown l.blue d.yellow
- green d.green bluegreen l.yellow
- With two new Standard Functions you can change the colour of PRINTed text
- (Ink$) or the colour of the background (Paper$). Both functions work on
- the TOS-screen only. The current resolution is checked in the Procedure
- Low.mode.
-
- (21) Nothing new in STANMED.LST, except the Procedure Med.mode to check
- the resolution.
-
- Perhaps you find all this talk about a "standard" program-structure very
- boring. If you write a program, why care about structure? Because it's
- much easier to change a structured program, especially if you didn't write
- the program yourself. Change an unstructured program, and you're going to
- be surprised by some (hidden) unwanted side-effects. Make other users
- happy, spread your beautiful programs only if they are structured and well
- commented. Do spread the (listable) source of your program, so other users
- can learn from you. And don't be insulted if others improve your program.
- I certainly will not be insulted if you send me your own thoughts about
- structured programming in GFA-Basic 3.0.
-
-
-
- START
-
- In the START-folder (in GFAXPRT2.ARC for downloaders) you will find the
- following programs :
- START.GFA - High or Medium resolution
- STARTLOW.GFA - Low resolution
- GFASTART.GFA - all resolutions
-
- I use two different disks for my GFA-programs. One for programs that run
- in High and/or Medium resolution (save the desktop in Medium resolution!).
- And one for programs that run in Low resolution.
-
- START.GFA and STARTLOW.GFA are used as a kind of shell to run the GFA-
- programs on these disks. Not a true shell, but it "feels" like all GFA-
- programs are run from START.GFA and STARTLOW.GFA. I start a GFA-session
- by double-clicking the shell-program on the desktop ('GFA' has been
- installed as application for GFABASIC.PRG).
-
- All my programs try to CHAIN one of the shell-programs when the user exits
- the program. Two important remarks if you decide to use these shell-
- programs :
- - vertical frequency is switched to 60 Hz in Medium or Low resolu-
- tion; not a good idea if you use a TV through a modulator!
- - Write Verify Test is switched off
- If you like, you can activate the check for a boot-virus in the shell-
- programs. The shell-program and GFABASIC.PRG (or GFABASRO.PRG) should be
- in the main directory!
-
- GFASTART.PRG is used in the same way with compiled GFA-programs. All my
- compiled GFA-programs try to CHAIN this shell-program when exiting. The
- source for this program is GFASTART.GFA. Compile this as GFASTART.PRG and
- put it in the main directory.
-
- All three START-programs contain plenty comments, so you should be able to
- understand how the programs work by studying the listings. The shell-
- programs certainly can be improved, I'm not yet satisfied with the current
- programs.
-
-
- small print
-
- Read this paragraph carefully, before using the GFAXPERT-files. The files
- are not Public Domain!
-
- You are free to use and change all GFAXPERT-files, but only for personal
- use. Certainly not for commercial use.
-
- You are invited to copy the original GFAXPERT-disk or the GFAXPRTx.ARC-
- files and give these to your friends. But you are not allowed to change
- anything on the disk or in the files. If you feel the urge to change
- something, don't do it, but write to me (read the chapter 'EPILOGUE').
-
- You are not allowed to sell (files from) the GFAXPERT-disk or one of the
- GFAXPRTx.ARC-files. The disk GFAXPERT may only be sold by so-called Public
- Domain Clubs if they have my written permission to do so. BBS's are free
- to make the original GFAXPRTx.ARC-files available for downloading.
-
- Any part from the text GFAXPERT.DOC or the Procedure-library GFAXPERT.LIB
- may be quoted in newsletters or magazines, if accompanied by a reference
- like :
- from GFAXPERT (2nd ed.) by Han Kempen
-
- I cannot be held responsible for any damage that may result from running a
- GFAXPERT-program, using a Procedure from the library GFAXPERT.LIB, or
- using information from this text.
-
-
- (c) Han Kempen, 3 July 1990
-
-
- EPILOGUE
-
-
- Well, that's all folks. I'm quite certain there are still a few bugs to be
- found in this text and in the Procedure-Library GFAXPERT.LIB. By now you
- should have become an expert in GFA-Basic 3.0, so you will be able to spot
- them bugs immediately. Please let me know if you find one.
-
- Perhaps you still have some unanswered questions about GFA-Basic. Or an
- answer to one of my own questions in this text. Or some neat Procedures.
- Or a brilliant program. I would appreciate it very much if you would send
- your letter and/or disk to :
-
- Han Kempen
- Rubensstraat 12
- 7741 AR Coevorden
- the Netherlands
-
- Do share your ideas, Procedures and programs with others, starting with
- me. Consider it a small payment for the GFAXPERT-files. Thanks.
-
-
-
-
-
-
- Wishing you many happy hours with GFA-Basic 3.0,
-
-
- Han Kempen
-
-
- INDEX
-
-
-
- (#) = Procedure or Function
-
-
- \ ..................................... 29
- " ..................................... 41
- 1st Word Plus ......................... 62
- 40-folder limit ....................... 66
-
- abbreviated commands .................. 12
- accessory ............................. 25,101
- ACHAR ................................. 96
- ACLIP ................................. 99
- After$ (#) ............................ 32
- AFTER ................................. 82
- ALERT ................................. 106
- application ........................... 9
- ARECT ................................. 88
- ASCII-code ............................ 33,34,36,37
- Ascii.qsort (#) ....................... 27
- ATEXT ................................. 96
- attribute ............................. 53
- AUTO .................................. 9
-
- BCHG .................................. 30
- BCLR .................................. 29
- Before$ (#) ........................... 32
- Bezier-curve .......................... 92
- BGET .................................. 62
- BIOS 4 (Rwabs) ....................... 59
- BIOS 7 (Getbpb) ...................... 56,60
- BIOS 9 (Mediach) ..................... 60
- BIOS 10 (Drvmap) ...................... 51
- BIOS 11 (Kbshift) ..................... 36
- bit-mask .............................. 29
- Blitter (#) ........................... 99
- BLOAD ................................. 61
- Block.dimmer (#) ...................... 91
- Boolean ............................... 17
- boot .................................. 9,61
- BPB ................................... 56
- BPUT .................................. 62
- break ................................. 10
- Break (#) ............................. 110
- BSAVE ................................. 61
- BSET .................................. 30,79
- bug (GFA) ............................. 12,20,24,25,31,32,36,42,80,83,
- 84,92,96,97,101
- bug (TOS) ............................. 25,35,55,56,63,64,66,70,95,102
-
- calculations .......................... 79
- Caps (#) .............................. 39
- CapsLock .............................. 38
- CARD .................................. 31
- CHAIN ................................. 83
- Change.font (#) ....................... 44
- Change.midi.buffer (#) ................ 67
- Change.palette (#) .................... 85
- characters ............................ 16,34
- CHDIR ................................. 51,110
- CLEAR ................................. 19
- CLEARW ................................ 105
- CLIP .................................. 92
- CLOSEW ................................ 104
- cluster ............................... 58
- Coldstart (#) ......................... 9
- color ................................. 40
- Color.cycle (#) ....................... 86
- correlation ........................... 31
- COSQ .................................. 30
- CURVE ................................. 92
- Cut and Paste ......................... 13
- Cycle.once (#) ........................ 87
-
- DATE$ ................................. 22
- Day.of.week (#) ....................... 22
- Debug (#) ............................. 19,111
- DEFFILL ............................... 87
- DEFLINE ............................... 89
- DEFLIST ............................... 15
- DEFMARK ............................... 87
- DEFMOUSE .............................. 72
- DEFTEXT ............................... 89
- DEFWRD ................................ 17
- Degas-Pictures ........................ 97
- Degas.screendump (#) .................. 46
- DELAY ................................. 83
- Desk-submenu .......................... 103
- DESKTOP.INF ........................... 106
- DFREE ................................. 56,58
- Digital$ (#) .......................... 93
- DIM ................................... 19
- Dim.colors (#) ........................ 86
- DIR$() ................................ 50
- DIR ................................... 51
- Direct mode ........................... 15
- disk format ........................... 55
- disk-swap ............................. 60
- Do.sound (#) .......................... 76
- DRAW .................................. 91
- DTA-buffer ............................ 52
- DUMP .................................. 19
-
- Editor ................................ 71
- EQV ................................... 31
- ERASE ................................. 19,24
- ERROR ................................. 82
- EVERY ................................. 82
- EXEC .................................. 24,83
- EXIST ................................. 54
- Exit (#) .............................. 110
-
- fade-over ............................. 99
- Fastprint (#) ......................... 41
- FAT ................................... 58
- FDC ................................... 55
- FGETDTA ............................... 52
- File Allocation Table ................. 58
- File.copy (#) ......................... 55
- File-submenu .......................... 103
- FILES ................................. 51
- FILESELECT ............................ 63
- Fileselect (#) ........................ 64
- Fileselector .......................... 63,71
- floating point ........................ 18
- Floppy Write Test ..................... 50
- Folded Procedures ..................... 13
- font .................................. 43,89
- Font.8x16 (#) ......................... 43
- Font.8x8 (#) .......................... 43
- FONTKIT ............................... 44
- FOR ... NEXT .......................... 79
- Force.mediach (#) ..................... 60
- FORM_ALERT ............................ 106
- FSETDTA ............................... 52
- FSFIRST ............................... 52
- FSNEXT ................................ 52
- Full.fill (#) ......................... 88
- FULLW ................................. 104
- FUNCTION .............................. 19
-
- GEMDOS 17 (Cprnos) .................... 45
- GEMDOS 25 (Dgetdrv) ................... 50
- GEMDOS 48 (Sversion) .................. 10
- GEMDOS 54 (Dfree) ..................... 56
- GEMDOS 67 (Fattrb) .................... 53
- GET ................................... 96
- Get.path (#) .......................... 110
- GFA-windows ........................... 104
- GFAXPERT.DOC .......................... 7,108
- GFAXPERT.LIB .......................... 7,108
- GOSUB ................................. 82
- GOTO .................................. 82
- GRAPHMODE ............................. 90
-
- HARDCOPY .............................. 45
- harddisk .............................. 51,55,58,59
- High.screendump.epson (#) ............. 45
- High.screendump.star24 (#) ............ 45
- HLINE ................................. 96
-
- IBOX .................................. 102
- IF ... ENDIF .......................... 78
- INFOW ................................. 194
- Initio (#) ............................ 109
- Initio.fill1 (#) ...................... 88
- Initio.high.fill1 (#) ................. 87
- Initio.keyget (#) ..................... 36
- Initio.logical.screen (#) ............. 42
- Initio.mouse1 (#) ..................... 72
- Initio.printer (#) .................... 47
- Initio.sound (#) ...................... 75
- Initio.sprite1 (#) .................... 93
- Initio.text.array (#) ................. 62
- Ink$ (#) .............................. 40
- INKEY$ ................................ 33
- INLINE ................................ 24,108
- INP ................................... 62,67,70
- INPAUX$ ............................... 70
- INPMID$ ............................... 67
- INPUT ................................. 34,62
- INPUT$ ................................ 35
- Insert-mode ........................... 15
- INSTR ................................. 32
- INT{} ................................. 23
- integer ............................... 18
- Intel.word (#) ........................ 31
- interleave ............................ 57
- Invert.block (#) ...................... 91
-
- joystick .............................. 74
-
- Key.click (#) ......................... 38
- Key.repeat (#) ........................ 39
- keyboard .............................. 37
- keyboard-buffer ....................... 33
- Keyboard.version (#) .................. 37
- KEYDEF ................................ 37
- KEYGET ................................ 35
- KEYLOOK ............................... 36
- KEYPAD ................................ 37
- KEYPRESS .............................. 37
- KEYTEST ............................... 35
- KILL .................................. 54
-
- Line-A ................................ 95
- LINE INPUT ............................ 35,62
- Llist ................................. 14
- Load .................................. 13
- LOCATE ................................ 41
- LOF ................................... 54
- LOG ................................... 30
- logical screen ........................ 42
- loops ................................. 80,119
- LSET .................................. 32
-
- Make.high.fill (#) .................... 88
- Make.mouse (#) ........................ 73
- Make.palette.string (#) ............... 85
- Make.sprite (#) ....................... 94
- MALLOC ................................ 25
- MAX ................................... 31,78
- Max.array (#) ......................... 31
- memory ................................ 23,24,25
- MENU() ................................ 101
- Midi-buffer ........................... 67
- Midi-commands ......................... 67
- Midi.monitor (#) ...................... 68
- MIN ................................... 78
- MOD ................................... 29
- monitor ............................... 10
- MOUSE ................................. 71
- MS-DOS disk ........................... 58
-
- NAME .................................. 54
- Neochrome-Pictures .................... 98
- New.med.colors (#) .................... 85
- Normal.font (#) ....................... 44
- NOT ................................... 81
-
- OBOX .................................. 102
- ON BREAK GOSUB ........................ 82
- ON MENU BUTTON ........................ 101
- ON MENU IBOX .......................... 102
- OPENW ................................. 104
- OPENW 0 ............................... 103
- Operating System ...................... 10
- OUT ................................... 40,62
- Overwrite-mode ........................ 15
-
- palette ............................... 84,111
- Palette.box (#) ....................... 86
- Paper$ (#) ............................ 40
- Parse.filename (#) .................... 65
- parser ................................ 32
- PCIRCLE ............................... 92
- physical screen ....................... 42
- Play.midi (#) ......................... 68
- PLOT .................................. 91
- point-commands ........................ 14
- PRED .................................. 29
- PRINT ................................. 40
- Print.stopwatch (#) ................... 21
- PRINT TAB ............................. 42
- printer-commands ...................... 47
- printer-driver ........................ 14
- printer-parameters .................... 45
- Printer.ready (#) ..................... 45
- PUT ................................... 96
-
- QSORT ................................. 26
-
- RAM ................................... 23
- RAM-disk .............................. 50
- READ .................................. 20
- RECALL ................................ 62
- Record.midi (#) ....................... 67
- RESERVE ............................... 23
- reset ................................. 9,50
- RESTORE ............................... 20
- Restore.palette (#) ................... 85
- Restore.physical.screen (#) ........... 43
- Return (#) ............................ 110
- reverse ............................... 41,84
- Rgb.value (#) ......................... 85
- right justification ................... 32
- RS232-buffer .......................... 70
- RSET .................................. 32
- Rubber.line (#) ....................... 90
-
- samples ............................... 76
- Save .................................. 14
- Save,A ................................ 14
- Save.palette (#) ...................... 85
- scan-code ............................. 33,36,37,38
- scrap-library ......................... 83
- Screen.dimmer (#) ..................... 91
- Screendump (#) ........................ 45
- Scroll.text.up (#) .................... 99
- Scroll.up (#) ......................... 98
- sectors ............................... 59
- SELECT ................................ 78
- serial number ......................... 57
- SETCOLOR .............................. 84
- SETMOUSE .............................. 71
- SHEL_GET .............................. 106
- SHEL_PUT .............................. 106
- shell-program ......................... 112
- SHL ................................... 79
- Show.degas (#) ........................ 97
- Show.text.page (#) .................... 63
- Shuffle (#) ........................... 20
- SINQ .................................. 30
- SOUND ................................. 75
- Soundmachine .......................... 77
- special characters .................... 16
- speech ................................ 77
- SPRITE ................................ 93
- SSORT ................................. 26
- Standard .............................. 7
- Standard Array ........................ 109,111
- Standard Functions .................... 110,111
- Standard Globals ...................... 109,111
- STANxxxx.LST .......................... 108
- START ................................. 112
- start-up .............................. 9
- Step Rate ............................. 50
- STICK ................................. 74
- Stopwatch (#) ......................... 21
- STORE ................................. 62
- STRIG ................................. 74
- String.index.qsort (#) ................ 28
- SUCC .................................. 29
- supervisor mode ....................... 23
- SWAP .................................. 20,31
- Swap.screen (#) ....................... 43
- syntax ................................ 12
- system-font ........................... 43,89
-
- Tab ................................... 13,41
- TAB ................................... 42
- TEXT .................................. 92
- text-array ............................ 62
- Text.at (#) ........................... 92
- TIME$ ................................. 21
- Time (#) .............................. 21
- TIMER ................................. 21
- Title.screen (#) ...................... 110
- TITLEW ................................ 104,105
- TOS ................................... 10
- TOS-screen ............................ 40
- TOUCH ................................. 54
- twisted format ........................ 57
- TYPE .................................. 20
-
- VAR ................................... 18
- variable type ......................... 17
- VDISYS 38 (vqt_attributes) ............ 89
- VQT_EXTENT ............................ 95
- VSETCOLOR ............................. 84
- VSYNC ................................. 98
- VT52 .................................. 40
-
- Warmstart (#) ......................... 9
- WAVE .................................. 75
- WIND_CLOSE ............................ 104
- word .................................. 17,31
- WORD .................................. 23,59
- write-protect ......................... 60
-
- XBIOS 0 (Initmous) ................... 71
- XBIOS 5 (Setscreen) .................. 42
- XBIOS 6 (Setpalette) ................. 85,97
- XBIOS 7 (Setcolor) ................... 84
- XBIOS 8 (Floprd) ..................... 60
- XBIOS 10 (Flopfmt) .................... 56
- XBIOS 15 (Rsconf) ..................... 70
- XBIOS 16 (Keytbl) ..................... 37,38
- XBIOS 18 (Protobt) .................... 57
- XBIOS 19 (Flopver) .................... 56
- XBIOS 32 (Dosound) .................... 75
- XBIOS 33 (Setprt) ..................... 45
- XBIOS 36 (Prtblk) ..................... 47
- XBIOS 64 (Blitmode) ................... 99
-
-